package com.ctshk.rpc.order.ship.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.CurrencyRateExchangeConstant;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.Currency;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.common.utils.*;
import com.ctshk.common.vo.OrderRefundDTO;
import com.ctshk.rpc.booking.enums.SupplierReserveTypeEnum;
import com.ctshk.rpc.booking.req.system.SupplierOrderSystemFreeCallConfirmReq;
import com.ctshk.rpc.booking.req.system.SystemConfirmReq;
import com.ctshk.rpc.booking.req.system.ship.add.SupplierOrderSystemShipAddReq;
import com.ctshk.rpc.booking.req.system.ship.add.SupplierSystemOrderShipAddReq;
import com.ctshk.rpc.booking.req.system.ship.add.SupplierSystemOrderShipTicketAddReq;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.finance.json.AccountJson;
import com.ctshk.rpc.finance.json.FileJson;
import com.ctshk.rpc.finance.req.bill.BillAddCollectionReq;
import com.ctshk.rpc.finance.req.bill.BillAddRefundReq;
import com.ctshk.rpc.finance.req.bill.BillOperateRefundReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.insurance.dto.InsuranceDTO;
import com.ctshk.rpc.insurance.dto.OfferDTO;
import com.ctshk.rpc.insurance.req.tp.Offer;
import com.ctshk.rpc.insurance.req.tp.OfferReq;
import com.ctshk.rpc.insurance.service.IInsuranceService;
import com.ctshk.rpc.iotc.dto.OperateBankPreferenceQueryDTO;
import com.ctshk.rpc.iotc.req.OperateBankConformQueryReq;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.order.ship.dto.ShipConstants;
import com.ctshk.rpc.order.ship.dto.ShipProductChannelOfflineSelfCustomDTO;
import com.ctshk.rpc.order.ship.dto.ShipProductCostTouristDTO;
import com.ctshk.rpc.order.ship.dto.ShipReserveDTO;
import com.ctshk.rpc.order.ship.dto.*;
import com.ctshk.rpc.order.ship.entity.*;
import com.ctshk.rpc.order.ship.enums.ShipCompanyEnums;
import com.ctshk.rpc.order.ship.generator.ShipOrderGenerator;
import com.ctshk.rpc.order.ship.mapper.*;
import com.ctshk.rpc.order.ship.req.*;
import com.ctshk.rpc.order.ship.service.IShipOrderReceiptService;
import com.ctshk.rpc.order.ship.service.IShipOrderService;
import com.ctshk.rpc.ship.dto.ShipReserveListDTO;
import com.ctshk.rpc.ship.dto.*;
import com.ctshk.rpc.ship.req.*;
import com.ctshk.rpc.ship.service.IShipProductSaleRecordService;
import com.ctshk.rpc.ship.service.IShipProductService;
import com.ctshk.rpc.ship.service.ZJShipProductService;
import com.ctshk.rpc.system.dto.MainDataCurrencyListDTO;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.SysDepartmentDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.dto.member.ContactQueryDTO;
import com.ctshk.rpc.system.req.MainDataCurrencyListReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberQueryReq;
import com.ctshk.rpc.system.service.ICrmMemberService;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.ISysDepartmentService;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.util.CollectionUtil;
import com.github.kfcfans.powerjob.client.OhMyClient;
import com.github.kfcfans.powerjob.common.response.ResultDTO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 船票订单 服务实现类
 * </p>
 *
 * @author 刘蕾
 * @since 2021-03-16
 */
@DubboService
public class ShipOrderServiceImpl extends ServiceImpl<ShipOrderMapper, ShipOrder> implements IShipOrderService , BaseService {


    @DubboReference
    private IShipProductService iShipProductService;

    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;

    @Autowired
    private ShipOrderTouristMapper shipOrderTouristMapper;

    @Autowired
    private ShipOrderMapper shipOrderMapper;

    @Autowired
    private ISysDepartmentService iSysDepartmentService;

    @Autowired
    private ShipManualOrderMapper shipManualOrderMapper;

    @Autowired
    private ShipOrderCollectionMapper shipOrderCollectionMapper;

    @Autowired
    private ShipOrderRouteMapper shipOrderRouteMapper;

    @Autowired
    private ShipOrderRefundMapper shipOrderRefundMapper;

    @Autowired
    private ShipOrderInsuranceMapper shipOrderInsuranceMapper;


    @DubboReference
    ICrmMemberService crmMemberService;

    @DubboReference
    ISysUserService sysUserService;

    @DubboReference
    IFinanceBillService iFinanceBillService;

    @DubboReference
    private ISysApprovalService iSysApprovalService;

    @DubboReference
    IOperateBankPreferenceService operateBankPreferenceService;

    @DubboReference
    IShipOrderReceiptService iShipOrderReceiptService;

    @DubboReference
    ZJShipProductService zjShipProductService;

    @DubboReference
    private IShipProductSaleRecordService iShipProductSaleRecordService;

    /**
     * 供应商预订单
     */
    @DubboReference
    private ISupplierOrderService iSupplierOrderService;

    @DubboReference
    private ISysUserService iSysUserService;


    @Value("${schedule.config.domain}")
    private String domain;

    @Value("${schedule.config.app-name}")
    private String appName;

    @Value("${schedule.config.password}")
    private String password;

    @Value("${schedule.job-id.order.ship}")
    private long jobId;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @DubboReference
    private IInsuranceService iInsuranceService;

    /**
     * 根据订单id查询订单详细信息
     *
     * @param orderId 订单id
     * @return 订单消息
     */
    @Override
    public Result<ShipOrderInfoDetailDTO> queryOrderDetailInfo(Long orderId) {
        //根据订单id查询订单信息
        ShipOrderInfoDetailDTO shipOrderDetailDTO = null;
        try {
            ShipOrder shipOrder = shipOrderMapper.selectById(orderId);
            if (Objects.isNull(shipOrder)) {
                return Result.failed(SystemError.SHIP_PRODUCT_11032);
            }
            shipOrderDetailDTO = EntityUtil.copy(shipOrder, ShipOrderInfoDetailDTO.class);

            //船票外挂单
            ShipManualOrder shipManualOrder = shipManualOrderMapper.selectOne(new QueryWrapper<ShipManualOrder>().lambda().eq(ShipManualOrder::getOrderId, orderId));
            if (!Objects.isNull(shipManualOrder)) {
                ShipManualOrderDetailDTO shipManualOrderDetailDTO = EntityUtil.copy(shipManualOrder, ShipManualOrderDetailDTO.class);
                shipOrderDetailDTO.setShipManualOrderDetail(shipManualOrderDetailDTO);
            }

            //船票订单旅客信息
            List<ShipOrderTourist> shipOrderTouristList = shipOrderTouristMapper.selectList(new QueryWrapper<ShipOrderTourist>().lambda().eq(ShipOrderTourist::getOrderId, orderId));
            if (!CollectionUtils.isEmpty(shipOrderTouristList)) {
                List<ShipOrderTouristDetailDTO> shipOrderTouristDTOList = EntityUtil.copyList(shipOrderTouristList, ShipOrderTouristDetailDTO.class);
                shipOrderDetailDTO.setShipOrderTouristDetailList(shipOrderTouristDTOList);
            }

            //船票收款明细信息
            List<ShipOrderCollection> shipOrderCollectionList = shipOrderCollectionMapper.selectList(new QueryWrapper<ShipOrderCollection>().lambda().eq(ShipOrderCollection::getOrderId, orderId));
            if (!CollectionUtils.isEmpty(shipOrderCollectionList)) {
                List<ShipOrderCollectionDetailDTO> shipOrderCollectionDTOList = EntityUtil.copyList(shipOrderCollectionList, ShipOrderCollectionDetailDTO.class);
                shipOrderDetailDTO.setShipOrderCollectionDetailList(shipOrderCollectionDTOList);
            }

            //船票退款明细信息
            List<ShipOrderRefund> shipOrderRefundList = shipOrderRefundMapper.selectList(new QueryWrapper<ShipOrderRefund>().lambda().eq(ShipOrderRefund::getOrderId, orderId));
            if (!CollectionUtils.isEmpty(shipOrderRefundList)) {
                List<ShipOrderRefundDetailDTO> shipOrderRefundDTOList = EntityUtil.copyList(shipOrderRefundList, ShipOrderRefundDetailDTO.class);
                shipOrderDetailDTO.setShipOrderRefundDetailList(shipOrderRefundDTOList);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return Result.success(shipOrderDetailDTO);
    }

    @Override
    public Result supplieConfirmOrder(SystemConfirmReq systemConfirmReq, Long userId) {
        QueryWrapper<ShipOrder> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ShipOrder::getOrderNumber, systemConfirmReq.getSaleNumber());
        ShipOrder localFunOrder = shipOrderMapper.selectOne(wrapper);
        if(localFunOrder == null){
            throw new BusinessException(SystemError.LOCAL_FUN_18010);
        }
        localFunOrder.setScheduledStatus(systemConfirmReq.getReserveStatus());
        shipOrderMapper.updateById(localFunOrder);
        return Result.success(localFunOrder.getId());
    }

    @Override
    public Result cancelOrder(ShipOrderCheckReq shipOrderCheckReq, TokenUser user) {
        Result<ApprovalCheckDTO> result = iSysApprovalService.check(shipOrderCheckReq.getId(),user.getId(),shipOrderCheckReq.getStatus(),shipOrderCheckReq.getReason());
        if(result.isSuccess()) {
            if (result.getData().getIsFinish()) {
                ShipOrder shipOrder = shipOrderMapper.selectById(shipOrderCheckReq.getOrderId());
                if (shipOrder == null) {
                    throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
                }

                LocalDateTime nowLocalDateTime = LocalDateTime.now();
                shipOrder.setCancelStatus(shipOrderCheckReq.getStatus());
                shipOrder.setScheduledStatus(null);
                shipOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
                shipOrder.setModifiedId(user.getId());
                shipOrder.setGmtModified(nowLocalDateTime);
                shipOrderMapper.updateById(shipOrder);

                //更新退款状态
                QueryWrapper<ShipOrderRefund> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(ShipOrderRefund::getOrderId,shipOrder.getId());
                List<ShipOrderRefund> shipOrderRefunds = shipOrderRefundMapper.selectList(queryWrapper);
                if(!CollectionUtils.isEmpty(shipOrderRefunds)){
                    shipOrderRefunds.forEach(entity->{
                        entity.setStatus(shipOrderCheckReq.getStatus());
                        shipOrderRefundMapper.updateById(entity);
                    });
                }

                //校验实际退款金额不能大于 订单金额
                List<ShipRefundDTO> reqList = shipOrderCheckReq.getOrderRefundApprovalRecordReqList();
                if(com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(reqList)){
                    BigDecimal sums = new BigDecimal(0);
                    List<BigDecimal> bigDecimals = reqList.stream().filter(en->en.getApprovalAmount() != null).flatMap(en ->
                            Stream.of(en.getApprovalAmount())).collect(Collectors.toList());

                    for(BigDecimal amount : bigDecimals){
                        sums = sums.add(amount);
                    }
                    if(sums.compareTo(shipOrder.getOrderAmount()) > 0){
                        throw new BusinessException(SystemError.LOCAL_FUN_18014);
                    }

                    for(ShipRefundDTO dto : reqList){
                        if(dto.getId() == null){
                            throw new BusinessException(SystemError.LOCAL_FUN_18025);
                        }
                        UpdateWrapper<ShipOrderRefund> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.lambda().eq(ShipOrderRefund::getId, dto.getId());
                        updateWrapper.lambda().set(ShipOrderRefund::getActualRefundAmount,dto.getApprovalAmount());
                        shipOrderRefundMapper.update(null,updateWrapper);
                    }
                }
                //释放座位
                releaseTicket(shipOrder.getApiOrderNumber());

                //删除库存
                String productIds = shipOrder.getProductId();
                if(StringUtil.isNotEmpty(productIds)){
                    String[] ids = productIds.split(",");
                    for(String productId : ids){
                        iShipProductSaleRecordService.deleteRecord(shipOrder.getId(),Long.valueOf(productId));
                    }
                }
                //新增退款记录
                try {
                    refundAmountApply(shipOrderRefunds,shipOrder,user);
                } catch (Exception e) {
                    log.error("新增退款记录失败");
                }
            }
        }else {
            Result result1 = new Result();
            result1.setCode(result.getCode());
            result1.setMsg(result.getMsg());
            return result1;
        }
        return Result.success();
    }

    private void refundAmountApply(List<ShipOrderRefund> shipOrderRefunds, ShipOrder shipOrder, TokenUser user) {
        List<BillAddRefundReq> collect = shipOrderRefunds.stream().map(entity -> {
            BillAddRefundReq req = new BillAddRefundReq();
            req.setBillNumber(entity.getRefundNumber());
            req.setBusinessType(SystemBusinessType.SHIP_TICKET.getCode());
            req.setCollectionAmount(entity.getActualRefundAmount());
            req.setCurrencyId(entity.getCurrencyId());
            req.setCurrencyName(entity.getCurrency());
            req.setSaleOrderId(shipOrder.getId());
            req.setSaleOrderNumber(shipOrder.getOrderNumber());
            List<Long> idsList = Arrays.asList(shipOrder.getProductId().split(",")).stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            req.setProductId(idsList);
            req.setSaleUserId(shipOrder.getSalesmanId());
            req.setSaleUserName(shipOrder.getSalesmanName());
            req.setRefundTime(LocalDateTime.now());
            req.setRefundTypeId(entity.getRefundWayId());
            req.setRefundType(entity.getRefundWay());
            AccountJson json = new AccountJson();
            json.setCardNumber(entity.getRefundAccount());
            req.setRefundAccountJson(json);
            //汇率
            BigDecimal exchangeRate = iMainDataCurrencyService.getExchangeRate(entity.getCurrency(), CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);
            req.setExchangeRate(exchangeRate.doubleValue());

            //销售部门
            SysDepartmentDTO sysDepartmentDTO = iSysDepartmentService.queryByUserId(user.getId());
            if (sysDepartmentDTO != null) {
                req.setSaleDeptId(sysDepartmentDTO.getId());
            }

            return req;
        }).collect(Collectors.toList());
        iFinanceBillService.addRefund(collect);
    }

    @Override
    public Result<List<ShipOrderRefundListDTO>> list(ShipOrderRefundReq shipOrderRefundReq) {

        QueryWrapper<ShipOrderRefund> scenicOrderRefundQueryWrapper = new QueryWrapper<>();
        scenicOrderRefundQueryWrapper.eq("is_deleted",0);
        scenicOrderRefundQueryWrapper.eq("order_id",shipOrderRefundReq.getOrderId());
        List<ShipOrderRefund> list = shipOrderRefundMapper.selectList(scenicOrderRefundQueryWrapper);
        List<ShipOrderRefundListDTO> scenicOrderRefundListDTOS = new ArrayList<>();
        if(com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(list)){
            for(ShipOrderRefund scenicOrderRefund : list){
                ShipOrderRefundListDTO scenicOrderTouristDTO = EntityUtil.copy(scenicOrderRefund,ShipOrderRefundListDTO.class);
                //todo   上线去掉
                UserDTO userDTO = null;
                try {
                    userDTO = iSysUserService.loadUserByParam(scenicOrderRefund.getCreateId(), 1);
                    //申请人
                    scenicOrderTouristDTO.setCreateName(userDTO.getUsername());
                } catch (Exception e) {
                    throw new BusinessException(SystemError.USER_1002);
                }
                scenicOrderTouristDTO.setCurrency(scenicOrderRefund.getCurrency());
                scenicOrderRefundListDTOS.add(scenicOrderTouristDTO);
            }
        }
        return Result.success(scenicOrderRefundListDTOS);
    }

    @Override
    public Result<Long> confirmOrder(ShipProductOrderReq shipProductOrderReq, TokenUser currentUser) {
        ShipOrder shipOrder = shipOrderMapper.selectById(shipProductOrderReq.getOrderId());
        shipOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
        shipOrderMapper.updateById(shipOrder);

        //确认预订
        SupplierOrderSystemFreeCallConfirmReq callConfirmReq = new SupplierOrderSystemFreeCallConfirmReq();
        callConfirmReq.setSaleNumber(shipOrder.getOrderNumber());
        callConfirmReq.setSupplierOrderNumber(shipProductOrderReq.getSupplierOrder());
        iSupplierOrderService.freeCallSystemConfirm(callConfirmReq,currentUser.getId());
        return Result.success(shipOrder.getId());
    }

    @Override
    public Result<List<MyShipOrderDTO>> recentToNow(LocalDateTime recent, LocalDateTime now) {
        List<ShipOrder> orderList = baseMapper.selectList(Wrappers.<ShipOrder>lambdaQuery()
                .eq(ShipOrder::getIsDeleted,IsDeletedCode.NO.getCode())
                .ge(recent != null,ShipOrder::getGmtModified, recent)
                .le(ShipOrder::getGmtModified, now));
        List<MyShipOrderDTO> result = new ArrayList<>();
        for (ShipOrder shipOrder : orderList) {
            MyShipOrderDTO orderDTO = EntityUtil.copy(shipOrder, MyShipOrderDTO.class);
            List<ShipOrderRoute> shipOrderRouteList = shipOrderRouteMapper.selectList(Wrappers.<ShipOrderRoute>lambdaQuery()
                    .eq(ShipOrderRoute::getOrderId, shipOrder.getId()));
            orderDTO.setShipOrderRouteList(EntityUtil.copyList(shipOrderRouteList, MyShipOrderRouteDTO.class));
            result.add(orderDTO);
        }

        return Result.success(result);
    }

    @Override
    public Result<List<ShipOrderInsuranceDTO>> insuranceRecord(InsuranceReq insuranceReq) {
        QueryWrapper<ShipOrderInsurance> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(ShipOrderInsurance::getOrderId,insuranceReq.getOrderId());
        wrapper.lambda().in(ShipOrderInsurance::getProductId,insuranceReq.getProductIds());
        List<ShipOrderInsurance> shipOrderInsurances = shipOrderInsuranceMapper.selectList(wrapper);
        if(CollectionUtil.isEmpty(shipOrderInsurances)){
            return Result.success(null);
        }
        return Result.success(EntityUtil.copyList(shipOrderInsurances,ShipOrderInsuranceDTO.class));
    }

    @Override
    public Result<ShipOrderInfoDTO> queryOrderDetail(Long id) {
        ShipOrder shipOrder = baseMapper.selectById(id);
        if(shipOrder == null){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11032);
        }
        ShipOrderInfoDTO dtoDetail = ShipOrderInfoDTO.builder().orderNumber(shipOrder.getOrderNumber())
                .orderAmount(shipOrder.getOrderAmount()).gmtCreate(shipOrder.getGmtCreate())
                .salesMethods(shipOrder.getSalesMethods()).paymentStatus(shipOrder.getPaymentStatus()).scheduledStatus(shipOrder.getScheduledStatus())
                .cancelStatus(shipOrder.getCancelStatus()).businessType("船票").payExpireDate(shipOrder.getPayExpireDate())
                .productType(shipOrder.getProductType()).source(shipOrder.getSource()).salesmanName(shipOrder.getSalesmanName()).contactMobileAreaCode(shipOrder.getContactMobileAreaCode())
                .clientType(shipOrder.getAgencyCompany()).contactName(shipOrder.getContactName()).contactMobile(shipOrder.getContactMobile()).contactEmail(shipOrder.getContactEmail())
                .remark(shipOrder.getRemark()).tripType(shipOrder.getTripType()).receivableAmount(shipOrder.getReceivableAmount()).refundedAmount(shipOrder.getRefundedAmount()).build();


        //订单状态
        if (shipOrder.getPaymentStatus() == null || OrderPaymentStatus.UN_PAYMENT.getCode().equals(shipOrder.getPaymentStatus())) {
            dtoDetail.setOrderStatus(OrderStatus.UN_PAYMENT.getCode());
        } else if (OrderScheduledStatus.CONFIRM_RESERVE.getCode().equals(shipOrder.getScheduledStatus())) {
            dtoDetail.setOrderStatus(OrderStatus.CONFIRM_RESERVE.getCode());
        } else if (OrderScheduledStatus.RESERVE_SUCCESS.getCode().equals(shipOrder.getScheduledStatus())) {
            dtoDetail.setOrderStatus(OrderStatus.RESERVE_SUCCESS.getCode());
        } else if (OrderScheduledStatus.RESERVE_FAIL.getCode().equals(shipOrder.getScheduledStatus())) {
            dtoDetail.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());
        } else if (OrderPaymentStatus.ALREADY_CANCEL.getCode().equals(shipOrder.getPaymentStatus())) {
            dtoDetail.setOrderStatus(OrderStatus.ALREADY_CANCEL.getCode());
            dtoDetail.setCancelReason(shipOrder.getCancelReason());
        }

        //去程航線信息
        setSingleRouteInfo(dtoDetail,shipOrder);
        if(shipOrder.getTripType() == 2){
            //返程航線信息
            setBackRouteInfo(dtoDetail,shipOrder);
        }

        //是否有购买保险
        dtoDetail.setHasInsurance(0);
        Integer count = shipOrderInsuranceMapper.selectCount(Wrappers.<ShipOrderInsurance>lambdaQuery().eq(ShipOrderInsurance::getOrderId, shipOrder.getId()));
        if(count > 0){
            dtoDetail.setHasInsurance(1);
        }
        return Result.success(dtoDetail);
    }

    @Override
    public Result cancelOrderBeforePay(ShipCancelOrderReq cancelOrderReq, TokenUser user) {
        ShipOrder shipOrder = shipOrderMapper.selectById(cancelOrderReq.getOrderId());
        shipOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
        shipOrder.setScheduledStatus(null);
        shipOrder.setCancelStatus(null);
        shipOrder.setModifiedId(user.getId());
        shipOrder.setGmtModified(LocalDateTime.now());
        shipOrder.setCancelReason(cancelOrderReq.getRefundReason());
        shipOrderMapper.updateById(shipOrder);

        return Result.success(cancelOrderReq.getOrderId());
    }

    @Override
    public Result<BigDecimal> getOrderAmount(ShipOrderCheckReq shipOrderCheckReq, TokenUser currentUser) {
        ShipOrder shipOrder = shipOrderMapper.selectById(shipOrderCheckReq.getOrderId());
        if(shipOrder == null){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11032);
        }
        return Result.success(shipOrder.getOrderAmount());
    }

    @Override
    public Result<List<OrderRefundDTO>> refundRecords(Long orderId) {
        QueryWrapper<ShipOrderRefund> scenicOrderRefundQueryWrapper = new QueryWrapper<>();
        scenicOrderRefundQueryWrapper.eq("is_deleted",0);
        scenicOrderRefundQueryWrapper.eq("order_id",orderId);
        List<ShipOrderRefund> list = shipOrderRefundMapper.selectList(scenicOrderRefundQueryWrapper);
        List<OrderRefundDTO> orderRefundDTOS = new ArrayList<>();
        if(com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(list)){
            orderRefundDTOS = list.stream().map(entity->{
                OrderRefundDTO dto = new OrderRefundDTO();
                dto.setApprovalAmount(entity.getActualRefundAmount());
                dto.setBusinessType(SystemBusinessType.SHIP_TICKET.getCode());
                dto.setCurrency(entity.getCurrency());
                dto.setRefundAccount(entity.getRefundAccount());
                dto.setPaidInAmount(entity.getActualRefundAmount());
                dto.setRefundId(entity.getId());
                dto.setRefundNumber(entity.getRefundNumber());
                dto.setRefundDetail("");
                dto.setRefundReason(entity.getRefundReason());
                dto.setRefundType(entity.getRefundWay());
                dto.setRemark(entity.getRemark());
                dto.setTotalReceivables(entity.getRefundAmount());
                return dto;
            }).collect(Collectors.toList());
        }
        return Result.success(orderRefundDTOS);
    }

    @Override
    public Result confirmRefund(String refundNumber, Long userId) {
        ShipOrderRefund shipOrderRefund = shipOrderRefundMapper.selectOne(Wrappers.<ShipOrderRefund>lambdaQuery()
                .eq(ShipOrderRefund::getRefundNumber, refundNumber));
        if (shipOrderRefund == null) {
            //收款记录不存在
            return Result.failed(SystemError.SHIP_PRODUCT_11047);
        }
        shipOrderRefund.setStatus(ApprovalStatus.REFUND_SUCCESS.getCode());
        shipOrderRefund.setModifiedId(userId);
        shipOrderRefund.setGmtModified(LocalDateTime.now());
        shipOrderRefundMapper.updateById(shipOrderRefund);
        return Result.success();
    }

    @Override
    public Result deleteRefund(Long refundId, Long userId) {
        ShipOrderRefund shipOrderRefund = shipOrderRefundMapper.selectById(refundId);
        if(shipOrderRefund != null){
            if(!ApprovalStatus.REVIEW_NO.getCode().equals(shipOrderRefund.getStatus())){
                throw new BusinessException(SystemError.SHIP_PRODUCT_11049);
            }
            shipOrderRefundMapper.deleteById(refundId);
        }
        return Result.success();
    }

    @Override
    public Result notice(ShipOrderNoticeReq shipOrderNoticeReq) {
        return Result.success();
    }

    @Override
    public Result updateOrderPaymentStatus(Long orderId) {
        ShipOrder shipOrder = shipOrderMapper.selectById(orderId);
        if(shipOrder == null){
            return Result.failed(SystemError.LOCAL_FUN_18010);
        }
        if(OrderPaymentStatus.UN_PAYMENT.getCode().equals(shipOrder.getPaymentStatus())){
            shipOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
            shipOrder.setScheduledStatus(null);
            shipOrder.setGmtModified(LocalDateTime.now());
            shipOrderMapper.updateById(shipOrder);
        }
        return Result.success(orderId);
    }

    @Override
    public Result<List<ShipOrderAtbTicketDTO>> getAtbTicket(ShipTicketReq shipTicketReq) {
        return Result.success(Lists.newArrayListWithCapacity(1));
    }

    @Override
    public List<ShipOrderDTO> queryOrderDTOList(LocalDateTime start, LocalDateTime end) {
        return EntityUtil.copyList(baseMapper.selectList(Wrappers.<ShipOrder>lambdaQuery()
                .eq(ShipOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(ShipOrder::getGmtCreate, start)
                .le(ShipOrder::getGmtCreate, end)),ShipOrderDTO.class);
    }

    /**
     *
     *返程航線信息
     * @param dtoDetail
     * @param shipOrder
     */
    private void setBackRouteInfo(ShipOrderInfoDTO dtoDetail, ShipOrder shipOrder) {
        String productId = shipOrder.getProductId();
        if(StringUtil.isEmpty(productId)) {
            return;
        }
        String[] productIds = productId.split(",");
        if(productIds.length < 2){
            return;
        }
        Long id = Long.valueOf(productIds[1]);
        QueryWrapper<ShipOrderRoute> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipOrderRoute::getOrderId,shipOrder.getId());
        queryWrapper.lambda().eq(ShipOrderRoute::getProductId,id);
        ShipOrderRoute shipOrderRoute = shipOrderRouteMapper.selectOne(queryWrapper);
        if(shipOrderRoute != null){
            if(shipOrderRoute.getCompanyType() == 1L){
                dtoDetail.setCompanyName2("信德");
            }else {
                dtoDetail.setCompanyName2("珠江");
            }
            dtoDetail.setRouteName2(shipOrderRoute.getRouteName());
            dtoDetail.setArrCityName2(shipOrderRoute.getArrCityName());
            dtoDetail.setDepCityName2(shipOrderRoute.getDepCityName());
            dtoDetail.setDepPlaceName2(shipOrderRoute.getDepPlaceName());
            dtoDetail.setArrPlaceName2(shipOrderRoute.getArrPlaceName());
            dtoDetail.setCabinClassName2(shipOrderRoute.getCabinClassName());
            dtoDetail.setVoyage2(shipOrderRoute.getVoyage());
            //出发日期
            if(shipOrderRoute.getDepTime() != null){
                dtoDetail.setStartDate2(shipOrderRoute.getDepTime().toLocalDate());
            }
            dtoDetail.setShipTypeName2(shipOrderRoute.getShipTypeName());
            //开船时间
            dtoDetail.setStartTime2(shipOrderRoute.getBeginTime());

            ShipProductReserveInfoDTO reserveInfoDTO = iShipProductService.queryShipProductReserveDetail(id);
            if(reserveInfoDTO != null){
                dtoDetail.setTicketCollectionType1(reserveInfoDTO.getTicketCollectionType());
                dtoDetail.setTicketCollection1(reserveInfoDTO.getTicketCollection());
                dtoDetail.setExchangeMethod1(reserveInfoDTO.getExchangeMethod());
            }
        }

    }

    /**
     * 去程航線信息
     * @param dtoDetail
     * @param shipOrder
     */
    private void setSingleRouteInfo(ShipOrderInfoDTO dtoDetail, ShipOrder shipOrder) {
        String productId = shipOrder.getProductId();
        if(StringUtil.isEmpty(productId)) {
            return;
        }
        String[] productIds = productId.split(",");
        if(productIds.length < 1){
            return;
        }
        Long id = Long.valueOf(productIds[0]);
        QueryWrapper<ShipOrderRoute> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipOrderRoute::getOrderId,shipOrder.getId());
        queryWrapper.lambda().eq(ShipOrderRoute::getProductId,id);
        ShipOrderRoute shipOrderRoute = shipOrderRouteMapper.selectOne(queryWrapper);
        if(shipOrderRoute != null){
            if(shipOrderRoute.getCompanyType() == 1L){
                dtoDetail.setCompanyName1("信德船舶");
            }else {
                dtoDetail.setCompanyName1("珠江船舶");
            }
            dtoDetail.setRouteName1(shipOrderRoute.getRouteName());
            dtoDetail.setArrCityName1(shipOrderRoute.getArrCityName());
            dtoDetail.setDepCityName1(shipOrderRoute.getDepCityName());
            dtoDetail.setDepPlaceName1(shipOrderRoute.getDepPlaceName());
            dtoDetail.setArrPlaceName1(shipOrderRoute.getArrPlaceName());
            dtoDetail.setCabinClassName1(shipOrderRoute.getCabinClassName());
            dtoDetail.setVoyage1(shipOrderRoute.getVoyage());
            //出发日期
            if(shipOrderRoute.getDepTime() != null){
                dtoDetail.setStartDate1(shipOrderRoute.getDepTime().toLocalDate());
            }
            dtoDetail.setShipTypeName1(shipOrderRoute.getShipTypeName());
            //开船时间
            dtoDetail.setStartTime1(shipOrderRoute.getBeginTime());

            ShipProductReserveInfoDTO reserveInfoDTO = iShipProductService.queryShipProductReserveDetail(id);
            if(reserveInfoDTO != null){
                dtoDetail.setTicketCollectionType1(reserveInfoDTO.getTicketCollectionType());
                dtoDetail.setTicketCollection1(reserveInfoDTO.getTicketCollection());
                dtoDetail.setExchangeMethod1(reserveInfoDTO.getExchangeMethod());
            }
        }
    }

    /**
     * 订单中心-船票订单分页查询列表
     *
     * @param req
     * @return
     */
    @Override
    public PageResponse<ShipOrderPageDTO> queyList(ShipOrderPageReq req) {
        IPage<ShipOrderPageDTO> agentPage = new Page<>(req.getPageNo(), req.getPageSize());
        agentPage = shipOrderMapper.queryList(req, agentPage);
        List<ShipOrderPageDTO> shipOrderPageDTOList = agentPage.getRecords();
        if (!CollectionUtils.isEmpty(shipOrderPageDTOList)) {

        }
        PageResponse<ShipOrderPageDTO> result = new PageResponse<>(agentPage.getRecords(), agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    /**
     * 确认退款
     *
     * @param id
     * @param refundId
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result confirmRefund(Long id, Long refundId, Long userId) {

        ShipOrder shipOrder = shipOrderMapper.selectById(id);
        if (shipOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
        }
        if (!(shipOrder.getCancelStatus() == ApprovalStatus.REVIEW_YES.getCode())) {
            //审批成功状态的订单，才可以做确认退款操作
            throw new BusinessException(SystemError.SHIP_PRODUCT_11033);
        }
        QueryWrapper<ShipOrderRefund> shipOrderRefundQueryWrapper = new QueryWrapper<>();
        shipOrderRefundQueryWrapper.lambda().eq(ShipOrderRefund::getOrderId, id);

        List<ShipOrderRefund> shipOrderRefundList = shipOrderRefundMapper.selectList(shipOrderRefundQueryWrapper);
        boolean ifAllRefund = true;
        for (ShipOrderRefund shipOrderRefund : shipOrderRefundList) {
            if (refundId.equals(shipOrderRefund.getId())) {
                // 确认退款
                shipOrderRefund.setStatus(OrderRefundStatus.REFUND_SUCCESSFUL.getCode());
                shipOrderRefundMapper.updateById(shipOrderRefund);

                //財務-操作退款
                if(com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(shipOrderRefund.getRefundNumber())){
                    BillOperateRefundReq billOperateRefundReq = new BillOperateRefundReq();
                    billOperateRefundReq.setBillNumber(shipOrderRefund.getRefundNumber());
                    billOperateRefundReq.setBusinessType(SystemBusinessType.SHIP_TICKET.getCode());
                    billOperateRefundReq.setUserId(userId);

                    iFinanceBillService.operateRefund(billOperateRefundReq);
                }
            }
            /**
             * do something暂无支付方式主数据，5-银行优惠，会员积分，优惠券，
             * 除5以外的支付方式记录的状态，有一个不是退款成功，ifAllRefund为false
             */
            if (!(shipOrderRefund.getRefundWayId() == 5) && !(shipOrderRefund.getStatus() == OrderRefundStatus.REFUND_SUCCESSFUL.getCode())) {
                ifAllRefund = false;
            }
        }
        if (ifAllRefund) {
            // 全部已退款,更新状态
            shipOrder.setCancelStatus(OrderCancelStatus.ALREADY_REFUND.getCode());
            shipOrderMapper.updateById(shipOrder);
        }
        return Result.success();
    }

    /**
     * 取消订单
     *
     * @param cancelOrderReq
     * @param user
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result cancelApprove(ShipCancelOrderReq cancelOrderReq, TokenUser user) {

        ShipOrder shipOrder = shipOrderMapper.selectById(cancelOrderReq.getOrderId());
        if (shipOrder == null) {
            throw new BusinessException(SystemError.SHIP_PRODUCT_11006);
        }
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(cancelOrderReq.getShipOrderRefundCancelReqList())) {
            // 退款记录不能为空
            throw new BusinessException(SystemError.SHIP_PRODUCT_11031);
        }
        //审批状态 ，取消订单审批通过或正在审批中，不允许重复操作
        if(ApprovalStatus.REVIEWING.getCode().equals(shipOrder.getCancelStatus()) ||
                ApprovalStatus.REVIEW_YES.getCode().equals(shipOrder.getCancelStatus())){
            throw new BusinessException(SystemError.LOCAL_FUN_18013);
        }
        if (shipOrder.getPaymentStatus() == OrderPaymentStatus.ALREADY_PAYMENT.getCode() && shipOrder.getScheduledStatus() == OrderScheduledStatus.RESERVE_SUCCESS.getCode()) {
            // 已经付款，预订成功，不退不改
            throw new BusinessException(SystemError.SHIP_PRODUCT_11030);
        }

        Result<ApprovalStartDTO> result = iSysApprovalService.start(SystemBusinessType.SHIP_TICKET.getCode(),
                SysApprovalType.CANCEL_SHIP.getCode(),shipOrder.getId(),user.getId(),null, "1");

        if(result.isSuccess()){
            shipOrder.setCancelStatus(ApprovalStatus.REVIEWING.getCode());
            shipOrder.setGmtModified(LocalDateTime.now());
            shipOrder.setModifiedId(user.getId());
            shipOrder.setCancelReason(cancelOrderReq.getRefundReason());
            shipOrderMapper.updateById(shipOrder);

            LocalDateTime nowLocalDateTime = LocalDateTime.now();
            List<ShipOrderRefund> shipOrderRefundList = EntityUtil.copyList(cancelOrderReq.getShipOrderRefundCancelReqList(), ShipOrderRefund.class);
            for (ShipOrderRefund shipOrderRefund : shipOrderRefundList) {
                shipOrderRefund.setRefundNumber(OperateNumberGenerateUtil.generateRefundNumber(nowLocalDateTime));
                shipOrderRefund.setOrderId(cancelOrderReq.getOrderId());
                shipOrderRefund.setStatus(ApprovalStatus.REVIEWING.getCode());
                shipOrderRefund.setIsDeleted(IsDeletedCode.NO.getCode());
                shipOrderRefund.setCreateId(user.getId());
                shipOrderRefund.setGmtCreate(nowLocalDateTime);
                shipOrderRefundMapper.insert(shipOrderRefund);
            }
        }else {
            Result result1 = new Result();
            result1.setCode(result.getCode());
            result1.setMsg(result.getMsg());
            return result1;
        }
        return Result.success(Long.valueOf(shipOrder.getId()));

    }

    /**
     * 预订中心下单
     * 接口优化
     * @param reqList 预订中心订单入参
     * @return 返回值
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result payOrder(List<ShipOrderCollectionReq> reqList, TokenUser user) {

        /**-----------------------------------------订单基础数据准备------------------------------------------*/
        Long id = reqList.stream().findFirst().get().getOrderId();
        ShipOrder shipOrder = shipOrderMapper.selectById(id);
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        UserDTO userToken = sysUserService.loadUserByParam(user.getId(), 1);
        if (null == userToken) {
            return Result.failed(SystemError.USER_1002);
        }
        List<ShipOrderCollection> shipOrderCollectionList = EntityUtil.copyList(reqList, ShipOrderCollection.class);
        //资源信息列表
        List<String> resourceInfoList = Lists.newArrayList();
        //产品名称
        StringBuffer productNames = new StringBuffer();
        //产品编号
        StringBuffer productNumber = new StringBuffer();
        //存放产品id列表
        List<Long> ids = Lists.newArrayList();
        Set<String> supplierSize = Sets.newHashSetWithExpectedSize(2);
        /**-----------------------------------------订单操作------------------------------------------*/
        //1.訂單校驗
        Result checkResult = checkOrderData(shipOrder,nowLocalDateTime,reqList,user);
        if (checkResult != null) return checkResult;

        //2.收款記錄
        addOrderCollection(user, id, nowLocalDateTime, shipOrderCollectionList);

        //3.供应商预订单接口
        String productIds = shipOrder.getProductId();
        Integer isConfirm = 1;
        if (!StringUtils.isEmpty(productIds)) {
            String[] idArray = productIds.split(",");
            for (String productId : idArray) {
                ShipProductDetailDTO shipProductDetailDTO = iShipProductService.queryDetail(Long.valueOf(productId));
                //产品供应商不同，分别下2个供应商预订单
                if(supplierSize.size() == 0 || !supplierSize.contains(shipProductDetailDTO.getSupplierId())){
                    isConfirm = shipProductDetailDTO.getIsConfirm();
                    extracted(user, shipOrder, shipProductDetailDTO,supplierSize);
                }
                ids.add(Long.valueOf(productId));
                productNumber.append(shipProductDetailDTO.getCode() + "/");
                productNames.append(shipProductDetailDTO.getRouteName());
                resourceInfoList.add(shipProductDetailDTO.getDepPlaceName() + "-" + shipProductDetailDTO.getArrPlaceName());
            }
        }

        //4.訂單收據
        iShipOrderReceiptService.add(id, user);

        //5.更新訂單狀態
        shipOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
        //立即确认，则下单后自行确认 (0 立即确认, 1 二次确认)
        if(isConfirm == 0){
            shipOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
        }else {
            shipOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
        }
        shipOrder.setModifiedId(user.getId());
        shipOrder.setGmtModified(nowLocalDateTime);
        shipOrderMapper.updateById(shipOrder);

        //6.珠江API产品 调用确认预订API接口
        if (shipOrder.getProductType() ==2 && !confirmBookingRn(shipOrder.getApiOrderNumber(), shipOrder.getId().toString())) {
            return Result.failed(SystemError.SHIP_PRODUCT_11041);
        }

        //7.申請收款認款
        Result billResult = iFinanceBillService.addCollection(obtainBillCollection(user, id, shipOrder, userToken,
                shipOrderCollectionList, resourceInfoList, ids,productNumber,productNames));
        if (billResult.getCode() != 0){
            throw new BusinessException(SystemError.SHIP_PRODUCT_11042, billResult.getMsg());
        }
        return Result.success();
    }


    /**
     * 添加收款记录
     * @param user
     * @param id
     * @param nowLocalDateTime
     * @param shipOrderCollectionList
     */
    private void addOrderCollection(TokenUser user, Long id, LocalDateTime nowLocalDateTime, List<ShipOrderCollection> shipOrderCollectionList) {
        for (ShipOrderCollection shipOrderCollection : shipOrderCollectionList) {
            shipOrderCollection.setOrderId(id);
            shipOrderCollection.setStatus(1);
            shipOrderCollection.setCollectionNumber(ShipOrderGenerator.getCollectionNumber());
            shipOrderCollection.setId(SnowflakeIdWorker.nextId());
            shipOrderCollection.setSalerId(user.getId());
            shipOrderCollection.setSalerName(user.getUsername());
            shipOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
            shipOrderCollection.setCreateId(user.getId());
            shipOrderCollection.setGmtCreate(nowLocalDateTime);
            shipOrderCollectionMapper.insert(shipOrderCollection);
        }
    }

    /**
     * 校验订单数据
     *
     * @param shipOrder
     * @param nowLocalDateTime
     * @param reqList
     * @param user
     * @return
     */
    private Result checkOrderData(ShipOrder shipOrder, LocalDateTime nowLocalDateTime, List<ShipOrderCollectionReq> reqList, TokenUser user) {
        //1.支付超时
        if (nowLocalDateTime.isAfter(shipOrder.getPayExpireDate())) {
            // 支付超时
            return Result.failed(SystemError.SHIP_PRODUCT_11028);
        }

        // 收款金额
        BigDecimal amountCountHKD = BigDecimal.ZERO;
        for (ShipOrderCollectionReq shipOrderCollection : reqList) {
            // 获取对应汇率，计算支付金额
            BigDecimal crmExchangeRate = getCrmExchangeRateByName(shipOrderCollection.getCurrency());
            BigDecimal amountHKD;
            if (shipOrderCollection.getIsUnionpayDiscount() == 1) {
                //银联优惠，do something银行优惠校验接口待完善
                //優惠後的金額
                amountHKD = getAmountByBankReference(shipOrder, shipOrderCollection.getUnionpayDiscountId());
            } else if (shipOrderCollection.getCollectionWayId() == 1 || shipOrderCollection.getCollectionWayId() == 2) {
                //统计实收金额，用于CRM会员积分,1-现金、2-信用卡金额
                //收款金額*匯率
                amountHKD = shipOrderCollection.getCollectionAmount().multiply(crmExchangeRate);
            } else {
                amountHKD = shipOrderCollection.getCollectionAmount().multiply(crmExchangeRate);
            }
            amountCountHKD = amountCountHKD.add(amountHKD);
        }

        //2.校验应收价格
        if(amountCountHKD.compareTo(shipOrder.getOrderAmount()) < 0){
            return  Result.failed(SystemError.SHIP_PRODUCT_11050);
        }
        return null;
    }

    private List<BillAddCollectionReq> obtainBillCollection(TokenUser user, Long id, ShipOrder shipOrder, UserDTO userToekn, List<ShipOrderCollection> shipOrderCollectionList, List<String> resourceInfoList, List<Long> productIds, StringBuffer productNumber, StringBuffer productNames) {
        List<BillAddCollectionReq> billAddCollectionList = Lists.newArrayList();
        //获取航班信息
        shipOrderCollectionList.parallelStream().forEach(shipOrderCollection -> {
            BillAddCollectionReq billAddCollectionReq = new BillAddCollectionReq();
            //        单号
            billAddCollectionReq.setBillNumber(shipOrderCollection.getCollectionNumber());
            //        业务类型
            billAddCollectionReq.setBusinessType(SystemBusinessType.SHIP_TICKET.getCode());
            //        收款方式ID
            billAddCollectionReq.setCollectionWayId(shipOrderCollection.getCollectionWayId());
            //        收款方式
            billAddCollectionReq.setCollectionWayName(shipOrderCollection.getCollectionWay());
            //        收款类型ID
            billAddCollectionReq.setCollectionTypeId(CollectionTypeIdCode.FULL.getCode());
            //        收款类型
            billAddCollectionReq.setCollectionTypeName(CollectionTypeIdCode.FULL.getMsg());
            //        收款金额
            billAddCollectionReq.setCollectionAmount(shipOrderCollection.getCollectionAmount());
            //        币种ID
            billAddCollectionReq.setCurrencyId(shipOrderCollection.getCurrencyId());
            //        币种名称
            billAddCollectionReq.setCurrencyName(shipOrderCollection.getCurrency());
            //        汇率
            // 获取对应汇率，计算支付金额
            BigDecimal exchangeRate = iMainDataCurrencyService.getExchangeRate(shipOrderCollection.getCurrency(), CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);

            billAddCollectionReq.setExchangeRate(exchangeRate.doubleValue());
            //        收款时间
            billAddCollectionReq.setCollectionTime(LocalDateTime.now());
            //        收款凭证JSON
            try { //避免出行json格式不对导致异常
                billAddCollectionReq.setCollectionVoucherJsonList(
                        JSONArray.parseArray(shipOrderCollection.getCollectionCertificateJson(), FileJson.class)
                );
            } catch (JSONException e) {
                e.printStackTrace();
            }
            //        销售单号
            billAddCollectionReq.setSaleOrderNumber(shipOrder.getOrderNumber());
            //        销售单ID
            billAddCollectionReq.setSaleOrderId(id);
            //        产品ID
            billAddCollectionReq.setProductId(productIds);
            //        产品编号/团号
            if(productNumber.length() > 0){
                billAddCollectionReq.setProductNumber(productNumber.substring(0,productNumber.length()-1));
            }
            //        产品名称
            if(productNumber.length() > 0){
                billAddCollectionReq.setProductName(productNames.substring(0,productNames.length()-1));
            }
            //        资源信息
            billAddCollectionReq.setResourceInfo(resourceInfoList);
            //        销售人员ID
            billAddCollectionReq.setSaleUserId(user.getId());
            //        销售人员名称
            billAddCollectionReq.setSaleUserName(user.getNickname());
            //        销售部门ID
            billAddCollectionReq.setSaleDeptId(userToekn.getDeptId());
            //        用户ID
            billAddCollectionReq.setUserId(user.getId());
            billAddCollectionList.add(billAddCollectionReq);
        });
        return billAddCollectionList;
    }

    private void extracted(TokenUser user, ShipOrder shipOrder, ShipProductDetailDTO shipProductDetailDTO, Set<String> supplierSize) {
        //供应商预订单
        SupplierOrderSystemShipAddReq supplierOrderSystemShipAddReq = new SupplierOrderSystemShipAddReq();
//        订单类型
        supplierOrderSystemShipAddReq.setOrderType(null);
//        外挂单出票类型(1:门店出票, 2:后台出票)
        supplierOrderSystemShipAddReq.setTicketMode(null);
//        所属团期ID
        supplierOrderSystemShipAddReq.setScheduleId(null);
//        供应商ID不能为空供应商ID
        supplierOrderSystemShipAddReq.setSupplierId(Long.valueOf(shipProductDetailDTO.getSupplierId()));
//        供应商名称不能为空供应商名称
        supplierOrderSystemShipAddReq.setSupplierName(shipProductDetailDTO.getSupplierName());
//        供应商订单类型不能为空供应商订单类型(1:普通订单, 2:内部挂账订单)
        supplierOrderSystemShipAddReq.setSupplierOrderType("1");
//        供应商销售编号 / 部门ID不能为空 供应商销售编号 / 部门ID(根据 '供应商订单编号' 显示，1：供应商销售编号，2：部门ID)
        supplierOrderSystemShipAddReq.setOriginalSaleNumber(null);
//        业务类型不能为空业务类型, 枚举SystemBusinessType
        supplierOrderSystemShipAddReq.setBusinessType(SystemBusinessType.SHIP_TICKET.getCode());
//        预订类型不能为空预订类型, 枚举SupplierReserveTypeEnum
        supplierOrderSystemShipAddReq.setReserveTypeId(SupplierReserveTypeEnum.SHIP.getId());
//        产品类型不能为空产品类型，枚举ProductType
        supplierOrderSystemShipAddReq.setProductType(shipProductDetailDTO.getProductSource());
//        资源所属部门ID(当前用户部门ID)
        supplierOrderSystemShipAddReq.setDepartmentId(null);
//        资源所属部门
        supplierOrderSystemShipAddReq.setDepartment(null);
//        供应商联络人姓名
        /*supplierOrderSystemShipAddReq.setSupplierContactName(null);
//        供应商联络人电话区号
        supplierOrderSystemShipAddReq.setSupplierContactMobileAreaCode(null);
//        供应商联络人电话
        supplierOrderSystemShipAddReq.setSupplierContactMobile(null);
//        供应商联络人传真
        supplierOrderSystemShipAddReq.setSupplierContactFax(null);
//        供应商联络人邮箱
        supplierOrderSystemShipAddReq.setSupplierContactEmail(null);*/
//        销售单号(通用) 不能为空销售单号(通用)
        supplierOrderSystemShipAddReq.setSaleNumber(shipOrder.getOrderNumber());
//        产品编号(通用) 不能为空产品编号(通用)
        supplierOrderSystemShipAddReq.setProductNumber(shipProductDetailDTO.getCode());
//        产品名称(通用) 不能为空产品名称(通用)
        supplierOrderSystemShipAddReq.setProductName(shipProductDetailDTO.getCode());
//        总金额不能为空总金额
        supplierOrderSystemShipAddReq.setTotalFee(shipOrder.getOrderAmount());

        MainDataCurrencyQueryDTO currencyEntity = iMainDataCurrencyService.getExchangeCurrencyEntity("HKD", CurrencyRateExchangeConstant.MARKET_EXCHANGE_RATE_);
//        币种ID不能为空币种ID
        supplierOrderSystemShipAddReq.setCurrencyId(currencyEntity.getId());
//        币种不能为空币种
        supplierOrderSystemShipAddReq.setCurrency("HKD");
//        应付金额不能为空应付金额
        supplierOrderSystemShipAddReq.setPayableAmount(shipOrder.getReceivableAmount());
//        付款类型ID不能为空付款类型ID, 当值 '内部挂账' 时 'scheduleId' 不能为空,,枚举PayRefundMethod
//        supplierOrderSystemShipAddReq.setPayTypeId(null);
////        付款类型
//        supplierOrderSystemShipAddReq.setPayType(null);
////        供应商期望付款时间
//        supplierOrderSystemShipAddReq.setExpectedPayTime(null);
//        附件文件JSON
        supplierOrderSystemShipAddReq.setFilesJson(null);
//        确认状态
        supplierOrderSystemShipAddReq.setConfirmStatus(shipOrder.getScheduledStatus());
//        确认时间
        supplierOrderSystemShipAddReq.setConfirmTime(null);
//        供应商订单号
        supplierOrderSystemShipAddReq.setSupplierOrderNumber(null);
//        提交结算状态
//        supplierOrderSystemShipAddReq.setSubmitSettleStatus(null);
//        使用资源编号
        supplierOrderSystemShipAddReq.setResourceNumber(null);
//        使用资源产品名称
        supplierOrderSystemShipAddReq.setResourceProductName(null);
//        备注
        supplierOrderSystemShipAddReq.setRemark(null);
        supplierOrderSystemShipAddReq.setSaleType(SalesMethod.SINGLE_SALE.getCode());
//        船信息不能为空船信息
        SupplierSystemOrderShipAddReq supplierSystemOrderShipAddReq = new SupplierSystemOrderShipAddReq();
        supplierSystemOrderShipAddReq.setSupplierSystemOrderShipTicketAddReqList(buildShipDetail(shipProductDetailDTO,shipOrder));
        supplierOrderSystemShipAddReq.setSupplierSystemOrderShipAddReq(supplierSystemOrderShipAddReq);
        iSupplierOrderService.addSystemShip(supplierOrderSystemShipAddReq, user.getId());
        //产品是同一个供应商只下一次供应商预订单
        if(!StringUtils.isEmpty(shipProductDetailDTO.getSupplierId())){
            supplierSize.add(shipProductDetailDTO.getSupplierId());
        }
    }

    /**
     * 构建产品详情列表
     * @param shipProductDetailDTO
     * @param shipOrder
     * @return
     */
    private List<SupplierSystemOrderShipTicketAddReq> buildShipDetail(ShipProductDetailDTO shipProductDetailDTO, ShipOrder shipOrder) {
        List<SupplierSystemOrderShipTicketAddReq> supplierSystemOrderShipTicketAddReqList = new ArrayList<>();
        SupplierSystemOrderShipTicketAddReq req = new SupplierSystemOrderShipTicketAddReq();
        req.setShipId(shipProductDetailDTO.getId());
        req.setOrderId(shipOrder.getId());
        req.setTravelType(shipOrder.getTripType());

        Map<String,String> goMap = Maps.newHashMap();
        goMap.put("go",shipProductDetailDTO.getDepPlaceName());
        req.setGoLocationJson(JSON.toJSONString(goMap));
        Map<String,String> goMap2 = Maps.newHashMap();
        goMap.put("go",shipProductDetailDTO.getArrPlaceName());
        req.setDesLocationJson(JSON.toJSONString(goMap2));

        req.setBusNumber(shipProductDetailDTO.getVoyage());
        req.setStartTime(shipProductDetailDTO.getDepTimeStart());
        req.setEndTime(shipProductDetailDTO.getArrTimeStart());
        req.setTaxAmount(shipProductDetailDTO.getOtherFeePrice());

        ShipPriceReq shipPriceReq = new ShipPriceReq();
        shipPriceReq.setProductId(shipProductDetailDTO.getId());
        shipPriceReq.setQueryDate(shipOrder.getGmtCreate().toLocalDate());
        QueryWrapper<ShipOrderTourist> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipOrderTourist::getOrderId,shipOrder.getId());
        List<ShipOrderTourist> shipOrderTourists = shipOrderTouristMapper.selectList(queryWrapper);
        if(CollectionUtil.isNotEmpty(shipOrderTourists)){
            Result<Map<Integer, List<ShipBaseInfoDTO>>> mapResult = iShipProductService.queryShipPriceByDate(shipPriceReq);
            shipOrderTourists.forEach(entity->{
                if(mapResult.getData()!=null){
                    List<ShipBaseInfoDTO> orDefault = mapResult.getData().getOrDefault(entity.getTouristTypeId(), null);
                    if(CollectionUtil.isNotEmpty(orDefault)){
                        ShipBaseInfoDTO shipBaseInfoDTO = orDefault.stream().findFirst().orElse(null);
                        if(shipBaseInfoDTO != null){
                            //成本价
                            req.setSinglePrice(shipBaseInfoDTO.getCostPrice());
                            //税费
                            req.setTaxAmount(shipBaseInfoDTO.getTaxFee());
                        }
                    }
                }
                req.setTouristId(entity.getId());
                req.setTouristName(entity.getTouristName());
                supplierSystemOrderShipTicketAddReqList.add(req);
            });
        }
        return supplierSystemOrderShipTicketAddReqList;
    }

    private String sendZJApi(ApiShipOrderReq apiShipOrderReq, String orderId) {
        String saleOrderId = "";
        if (apiShipOrderReq.getProductId().indexOf(",") != -1) {
            String[] split = apiShipOrderReq.getProductId().split(",");
            for (String s : split) {
                List<ShipZJProductApiSubmitTicketsReq> ShipZJProductApiSubmitTickets = new ArrayList<>();
                List<ShipReserveListDTO> shipReserveListDTOS = iShipProductService.queryApiProductList(s, apiShipOrderReq.getTicketNumber());
                ShipReserveListDTO shipReserveListDTO = shipReserveListDTOS.get(0);
                ShipZJProductApiSubmitReq shipZJProductApiSubmitReq = new ShipZJProductApiSubmitReq();
                shipZJProductApiSubmitReq.setOrderId(orderId);
                shipZJProductApiSubmitReq.setStartDate(shipReserveListDTO.getStartDate());
                shipZJProductApiSubmitReq.setDepPlaceCode(shipReserveListDTO.getDepPlaceCode());
                shipZJProductApiSubmitReq.setArrPlaceCode(shipReserveListDTO.getArrPlaceCode());
                shipZJProductApiSubmitReq.setName(apiShipOrderReq.getContactName());
                shipZJProductApiSubmitReq.setEmail(apiShipOrderReq.getContactEmail());
                shipZJProductApiSubmitReq.setIsETicket("0");
                shipZJProductApiSubmitReq.setAddress(apiShipOrderReq.getContactMobile());
                shipZJProductApiSubmitReq.setCardNum(apiShipOrderReq.getCardNum());
                List<ShipOrderTouristReq> shipOrderTouristList = apiShipOrderReq.getShipOrderTouristList();
                for (ShipOrderTouristReq shipOrderTouristReq : shipOrderTouristList) {
                    ShipZJProductApiSubmitTicketsReq shipZJProductApiSubmitTicketsReq = new ShipZJProductApiSubmitTicketsReq();
                    shipZJProductApiSubmitTicketsReq.setSeatRankId(shipReserveListDTO.getCabinClassStr());
                    shipZJProductApiSubmitTicketsReq.setPrice(shipReserveListDTO.getCosPrice().setScale(0).toString());
                    shipZJProductApiSubmitTicketsReq.setTicketCode(shipReserveListDTO.getCostCode());
                    shipZJProductApiSubmitTicketsReq.setVoyage(shipReserveListDTO.getVoyage());
                    shipZJProductApiSubmitTicketsReq.setTouristTypeId(shipOrderTouristReq.getAppellation().toString());
                    shipZJProductApiSubmitTicketsReq.setName(shipOrderTouristReq.getTouristName());
                    shipZJProductApiSubmitTicketsReq.setIdNumber(shipOrderTouristReq.getCertificatesNumber());
                    shipZJProductApiSubmitTicketsReq.setIdType(shipOrderTouristReq.getCertificatesType());
                    ShipZJProductApiSubmitTickets.add(shipZJProductApiSubmitTicketsReq);
                }
                shipZJProductApiSubmitReq.setShipZJProductApiSubmitTickets(ShipZJProductApiSubmitTickets);
                Result<List<Map<String, Object>>> shipProductApiSubmitDTOResult = zjShipProductService.submitShipProduct(shipZJProductApiSubmitReq);
                //api銷售訂單號
                if (null != shipProductApiSubmitDTOResult) {
                    List<Map<String, Object>> data = shipProductApiSubmitDTOResult.getData();
                    for (Map<String, Object> datum : data) {
                        try {
                            saleOrderId += datum.get("MSGINFO").toString() + ",";
                        } catch (Exception e) {
                            log.error("sendZJApi NULLPOINT");
                        }
                    }
                }
            }
            if (!"".equals(saleOrderId)) {
                saleOrderId = saleOrderId.substring(0, saleOrderId.length() - 1);
            }
            //查询API接口需要的产品信息
        }
        return saleOrderId;
    }


    /**
     * 填写订单信息下单
     *
     * @param apiShipOrderReq
     * @param user
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result saveApiShipOrder(ApiShipOrderReq apiShipOrderReq, TokenUser user) {
        if (null == user) {
            return Result.failed(SystemError.USER_1000);
        }
        if (null == apiShipOrderReq) {
            return Result.failed(SystemError.SHIP_PRODUCT_11002);
        }
        //api接口返回的订单号
        String apiOrderNumber = "";
        try {
            //订单总额
            BigDecimal totalAmount = new BigDecimal(0);
            //单服务费
            BigDecimal serviceAmount = new BigDecimal(0);

            //成人总票数
            int adultTotalNumber = 0;
            //小童总票数
            int childrenTotalNumber = 0;
            //订单ID
            Long orderId = SnowflakeIdWorker.nextId();

            //订单保存的产品ID用逗号间隔
            String productIds = "";

            //是否单程或者往返
            int tripTypeFlag = 0;//默认单程
            //总orderDetail
            List<ShipOrderDetailListDTO> shipAllOrderDetailList = new ArrayList<>();
            //保存旅客及联系人
            List<ShipOrderTouristReq> shipOrderTouristList = apiShipOrderReq.getShipOrderTouristList();
            //1:获取产品信息
            boolean touristSwitch = true;
            List<ShipOrderRouteProductReq> shipOrderRouteProductList = apiShipOrderReq.getShipOrderRouteProductList();
            apiOrderNumber = sendZJApi(apiShipOrderReq, orderId.toString());
            for (ShipOrderRouteProductReq shipOrderRouteProductReq : shipOrderRouteProductList) {
                //成人总额
                BigDecimal adultAmount = new BigDecimal(0);
                //小童总额
                BigDecimal childrenAmount = new BigDecimal(0);
                //成人总税额
                BigDecimal adultTaxAmount = new BigDecimal(0);
                //小童总税额
                BigDecimal childrenTaxAmount = new BigDecimal(0);

                Long productId = 0l;
                int adultNumber = 0;
                int childrenNumber = 0;
                List<ShipReserveListDTO> shipReserveListDTOS = iShipProductService.queryApiProductList(apiShipOrderReq.getProductId(), apiShipOrderReq.getTicketNumber());
                if (CollectionUtils.isEmpty(shipReserveListDTOS)) {
                    return Result.failed(SystemError.SHIP_PRODUCT_11024);
                }
                ShipReserveListDTO shipReserveListDTO = shipReserveListDTOS.get(0);
                productId = shipReserveListDTO.getId();
                ShipReserveDTO shipReserveDTO = new ShipReserveDTO();
                BeanUtils.copyProperties(shipReserveListDTO, shipReserveDTO);
                List<ShipProductCostAndDateListDTO> shipProductCostAndDateListDTOS = iShipProductService.queryShipProductCostAndDateList(apiShipOrderReq.getId(), apiShipOrderReq.getStartDate(),user.getId().toString());
                //获取加幅
                com.ctshk.rpc.ship.dto.ShipReserveDTO shipProductReserveDTO = iShipProductService.queryOfflineSelfList(apiShipOrderReq.getId(), apiShipOrderReq.getStartDate()).get(0);
                ShipInitializationSettingsDTO shipInitializationSettingsDTO = iShipProductService.queryShipInitializationSettings();
                shipProductReserveDTO.setAdjustType(shipInitializationSettingsDTO.getBookingPriceType());
                shipProductReserveDTO.setPercent(shipInitializationSettingsDTO.getBookingPrice());
                shipProductReserveDTO.setOffLinePrice(new BigDecimal(shipInitializationSettingsDTO.getBookingPrice()));
                /**保存旅客信息 以及计算旅客成本*/
                for (ShipOrderTouristReq shipOrderTouristReq : shipOrderTouristList) {
                    ShipOrderTourist shipOrderTourist = new ShipOrderTourist();
                    BeanUtils.copyProperties(shipOrderTouristReq, shipOrderTourist);
                    shipOrderTourist.setOrderId(orderId);
                    shipOrderTourist.setGmtCreate(LocalDateTime.now());
                    shipOrderTourist.setCreateId(user.getId());
                    for (ShipProductCostAndDateListDTO shipProductCostAndDateListDTO : shipProductCostAndDateListDTOS) {
                        //称谓(1:先生;2:女士;3:小姐;4:男童;5:女童)")
                        int touristTypeId = Integer.parseInt(shipProductCostAndDateListDTO.getTouristTypeId().toString());
                        if (touristTypeId == shipOrderTourist.getAppellation()) {
                            if (touristTypeId == 1) {
                                adultAmount = adultAmount.add(shipProductCostAndDateListDTO.getCostPrice());
                                adultTaxAmount = adultTaxAmount.add(computeOffLinePrice(shipProductReserveDTO, shipProductCostAndDateListDTO.getCostPrice()));
                                adultNumber++;
                            } else if (touristTypeId == 2) {
                                childrenAmount = childrenAmount.add(shipProductCostAndDateListDTO.getCostPrice());
                                childrenTaxAmount = childrenTaxAmount.add(computeOffLinePrice(shipProductReserveDTO, shipProductCostAndDateListDTO.getCostPrice()));
                                childrenNumber++;
                            }
                            totalAmount = totalAmount.add(shipProductCostAndDateListDTO.getCostPrice());
                            totalAmount = totalAmount.add(computeOffLinePrice(shipProductReserveDTO, shipProductCostAndDateListDTO.getCostPrice()));
                        }
                    }
                    if (touristSwitch) {
                        shipOrderTouristMapper.insert(shipOrderTourist);
                    }
                }
                touristSwitch = false;
                tripTypeFlag++;
                /**保存订单的产品信息*/
                ShipOrderRouteReq shipOrderRouteReq = new ShipOrderRouteReq();
                BeanUtils.copyProperties(shipReserveDTO, shipOrderRouteReq);
                ShipOrderRoute shipOrderRoute = new ShipOrderRoute();
                BeanUtils.copyProperties(shipOrderRouteReq, shipOrderRoute);
                shipOrderRoute.setId(SnowflakeIdWorker.nextId());
                shipOrderRoute.setProductId(productId);
                shipOrderRoute.setOrderId(orderId);

                shipOrderRoute.setShipTypeName(shipReserveDTO.getShipTypeName());
                shipOrderRoute.setArrCityName(shipReserveDTO.getArrCityName());
                shipOrderRoute.setDepCityName(shipReserveDTO.getDepCityName());
                shipOrderRoute.setDepPlaceName(shipReserveDTO.getArrCityName());
                shipOrderRoute.setArrPlaceName(shipReserveDTO.getDepCityName());
                shipOrderRoute.setRouteName(shipReserveDTO.getRouteName());

                shipOrderRoute.setCompanyType(Long.valueOf(shipReserveDTO.getCompanyType()));
                shipOrderRoute.setGmtCreate(LocalDateTime.now());
                shipOrderRoute.setCreateId(user.getId());
                shipOrderRoute.setNumber(apiShipOrderReq.getTicketNumber());
                shipOrderRoute.setIsDeleted(ShipConstants.NOT_DELETE);

                List<ShipOrderDetailListDTO> shipOrderDetailList = computeAmount(adultAmount, childrenAmount, adultTaxAmount, childrenTaxAmount, adultNumber, childrenNumber, "HDK");
                shipOrderRoute.setOrderDetails(JSONUtil.toJsonStr(shipOrderDetailList));
                shipAllOrderDetailList.addAll(shipOrderDetailList);
                shipOrderRouteMapper.insert(shipOrderRoute);
                //累加票数
                adultTotalNumber += adultNumber;
                childrenTotalNumber += childrenNumber;

                productIds += shipReserveDTO.getId() + ",";
                /**先保存累加服务费*/
                serviceAmount = adultTaxAmount;

                /**保存产品库存售卖记录body*/
                ShipProductSaleRecordReq shipProductSaleRecordReq = new ShipProductSaleRecordReq();
                shipProductSaleRecordReq.setId(SnowflakeIdWorker.nextId());
                shipProductSaleRecordReq.setOrderId(orderId);
                shipProductSaleRecordReq.setProductId(productId);
                shipProductSaleRecordReq.setSalesDate(apiShipOrderReq.getStartDate());
                shipProductSaleRecordReq.setSoldNumber(apiShipOrderReq.getTicketNumber());
                //1:自营 2:代理商 3:官方渠道 4:第三方
                shipProductSaleRecordReq.setChannel(4);
                //1 线上 2线下
                shipProductSaleRecordReq.setLine(1);
                ////备注要加权限
//            shipProductSaleRecordReq.setCheckType(user.getId());
                shipProductSaleRecordReq.setCustomId(user.getId());
                shipProductSaleRecordReq.setCustomName(user.getUsername());
                iShipProductSaleRecordService.insertRecord(shipProductSaleRecordReq, user);

            }
            productIds = productIds.substring(0, productIds.length() - 1);
//        //推广码和积分待计算 TODO
            /**保存订单信息*/
            ShipOrder shipOrder = new ShipOrder();
            BeanUtils.copyProperties(apiShipOrderReq, shipOrder);
            //组装订单
            shipOrder.setId(orderId);
            shipOrder.setTripType(tripTypeFlag);//订单行程类型 1.单程 2往返
            shipOrder.setProductId(productIds);
            shipOrder.setGmtCreate(LocalDateTime.now());
            shipOrder.setCreateId(user.getId());
            shipOrder.setIsDeleted(ShipConstants.NOT_DELETE);
            //销售编号 TODO
//        shipOrder.setOrderNumber(buildProductNumber(user.getId(), LocalDateTime.now()));
            //產品
            shipOrder.setApiOrderNumber(apiOrderNumber);
//        // 计算应收金额 TODO
//        buildReceivableAmount(shipOrder, totalAmount);
            // 计算付款到期时间,+30分钟
            shipOrder.setPayExpireDate(LocalDateTime.now().plusMinutes(30));
            //单服务费*面票数
            serviceAmount = serviceAmount.multiply(new BigDecimal(adultTotalNumber + childrenTotalNumber));
            shipOrder.setServiceFee(serviceAmount);
            //订单总额
            shipOrder.setOrderAmount(totalAmount);
            shipOrder.setContactName(apiShipOrderReq.getContactName());
            shipOrder.setScheduledStatus(1); //已预订
            shipOrder.setPaymentStatus(1); //未付款
            shipOrder.setCancelStatus(0); //未取消
            shipOrder.setSalesmanId(user.getId());
            shipOrder.setSalesmanName(user.getUsername());
            shipOrder.setSalesMethods(1);//销售方式(1：单品销售 2：打包销售)
            shipOrder.setProductType(1);//产品类型(1手工单，2外挂单)
            shipOrder.setCreateId(user.getId());
            shipOrder.setOrderDetails(JSONUtil.toJsonStr(shipAllOrderDetailList));
            shipOrder.setGmtCreate(LocalDateTime.now());
            shipOrderMapper.insert(shipOrder);
            /**保险信息*/
            if (apiShipOrderReq.getBuyInsurance().intValue() == NumberConstant.ONE.getValue().intValue()) {
                List<ShipOrderInsuranceReq> shipOrderInsuranceReqList = apiShipOrderReq.getShipOrderInsuranceReqList();
                if (CollectionUtil.isEmpty(shipOrderInsuranceReqList)) {
                    new BusinessException(SystemError.AIR_ORDER_15005);
                }
                for (ShipOrderInsuranceReq shipOrderInsuranceReq : shipOrderInsuranceReqList) {
                    ShipOrderInsurance shipOrderInsurance = new ShipOrderInsurance();
                    BeanUtils.copyProperties(shipOrderInsuranceReq, shipOrderInsurance);
                    shipOrderInsurance.setId(SnowflakeIdWorker.nextId());
                    shipOrderInsurance.setOrderId(orderId);
                    shipOrderInsurance.setCreateId(user.getId());
                    shipOrderInsurance.setGmtCreate(LocalDateTime.now());
                    shipOrderInsurance.setIsDeleted(IsDeletedCode.NO.getCode());
                    shipOrderInsuranceMapper.insert(shipOrderInsurance);
                }
            }
        } catch (Exception e) {
            log.error("saveApiShipOrder-error" + e);
            //发生异常后去珠江船票那释放座位
            if (!releaseTicket(apiOrderNumber)) {
                return Result.failed(SystemError.SHIP_PRODUCT_11040);
            }
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//如果抛了异常,会回滚,不影响事物正常执行
        }
        return Result.success();
    }

    private boolean confirmBookingRn(String apiOrderNumber, String orderId) {
        if (null != apiOrderNumber || !"".equals(apiOrderNumber)) {
            if (apiOrderNumber.indexOf(",") != -1) {
                String[] split = apiOrderNumber.split(",");
                for (String s : split) {
                    if (!"1".equals(zjShipProductService.confirmBookingRn(s, orderId).toString())) {
                        return false;
                    }
                }
            } else {
                if (!"1".equals(zjShipProductService.confirmBookingRn(apiOrderNumber, orderId).toString())) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean releaseTicket(String apiOrderNumber) {
        if (null != apiOrderNumber || !"".equals(apiOrderNumber)) {
            if (apiOrderNumber.indexOf(",") != -1) {
                String[] split = apiOrderNumber.split(",");
                for (String s : split) {
                    if (!"1".equals(zjShipProductService.releaseTicket(s).toString())) {
                        return false;
                    }
                }
            } else {
                if (!"1".equals(zjShipProductService.releaseTicket(apiOrderNumber).toString())) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 填写订单信息下单
     * 接口已优化
     * @param shipOrderReq
     * @param user
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result saveShipOrder(ShipOrderReq shipOrderReq, TokenUser user) {
        if (null == user) {
            return Result.failed(SystemError.USER_1000);
        }
        if (null == shipOrderReq) {
            return Result.failed(SystemError.SHIP_PRODUCT_11002);
        }

        /**---------------------------------------------定义订单信息 开始-------------------------------------------------**/
        ShipOrderAmountItem shipOrderAmountItem = new ShipOrderAmountItem();
        //成人总票数
        AtomicInteger adultTotalNumber = new AtomicInteger(0);
        //小童总票数
        AtomicInteger childrenTotalNumber = new AtomicInteger(0);
        //订单保存的产品ID用逗号间隔
        StringBuffer productIds = new StringBuffer();
        //是否单程或者往返 , 默认单程
        AtomicInteger tripTypeFlag = new AtomicInteger(0);
        //总orderDetail
        List<ShipOrderDetailListDTO> shipAllOrderDetailList = Lists.newArrayListWithExpectedSize(5);
        //同一个订单，仅插入一次旅客信息
        AtomicBoolean touristSwitch = new AtomicBoolean(true);
        //旅客Id映射关系
        Map<Long,ShipOrderTourist> touristMap = Maps.newHashMap();
        //去程、返程 旅客船票價格映射
        Map<Long,Map<Integer,BigDecimal>> priceMap = Maps.newHashMap();
        //去程、返程 旅客稅費映射
        Map<Long,BigDecimal> taxMap = Maps.newHashMap();
        /**----------------------------------------------定义订单信息 结束------------------------------------------------**/


        //1.订单ID  保存订单相关信息
        Long orderId = SnowflakeIdWorker.nextId();
        for (ShipOrderRouteProductReq shipOrderRouteProductReq : shipOrderReq.getShipOrderRouteProductList()) {
            ShipProductIsRecommendedReq shipProductIsRecommendedReq = queryShipInfo(shipOrderRouteProductReq,shipOrderRouteProductReq);
            shipProductIsRecommendedReq.setId(Long.valueOf(shipOrderRouteProductReq.getProductId()));
            List<ShipReserveListDTO> shipReserveListDTOS = iShipProductService.queryReserveList(shipProductIsRecommendedReq, user,null);
            if (CollectionUtils.isEmpty(shipReserveListDTOS)) {
                return Result.failed(SystemError.SHIP_PRODUCT_11024);
            }
            //<1>.获取航线的产品信息
            ShipReserveListDTO shipReserveListDTO = shipReserveListDTOS.get(0);

            //<2>.保存订单的旅行信息
            ShipReserveDTO shipReserveDTO = saveOrderTouristInfo(shipOrderRouteProductReq.getProductId(), user, touristMap, shipOrderAmountItem, adultTotalNumber, childrenTotalNumber, orderId, shipOrderReq.getShipOrderTouristList(), touristSwitch.get(), shipReserveListDTO,shipOrderRouteProductReq.getStartDate(),priceMap);

            //<3>.保存订单的航线信息  往返票/单程票-航线信息
            saveShipOrderRoute(user, shipOrderAmountItem.getAdultAmount(), shipOrderAmountItem.getChildrenAmount(),
                    shipOrderAmountItem.getAdultTaxAmount(), shipOrderAmountItem.getChildrenTaxAmount(), orderId, shipAllOrderDetailList, shipOrderRouteProductReq, shipReserveListDTO, shipOrderAmountItem.getAdultNumber(), shipOrderAmountItem.getChildrenNumber(), shipReserveDTO);

            //<4>.减产品库存
            saveSaleRecord(user, orderId, shipOrderRouteProductReq, shipReserveListDTO.getId());

            //<5>.其他
            //拼接产品信息
            productIds.append(shipReserveDTO.getId() + ",");
            shipOrderAmountItem.getDepCity().append(shipReserveListDTO.getDepCityName() + "/");
            shipOrderAmountItem.getArrCity().append(shipReserveListDTO.getArrCityName() + "/");
            shipOrderAmountItem.getDepPlace().append(shipReserveListDTO.getDepPlaceName() + "/");
            shipOrderAmountItem.getArrPlace().append(shipReserveListDTO.getArrPlaceName() + "/");
            shipOrderAmountItem.getVoyage().append(shipReserveListDTO.getVoyage() + "/");
            shipOrderAmountItem.getCompanyType().append(ShipCompanyEnums.getCompanyName(shipReserveListDTO.getCompanyType()) +"/");
            shipOrderAmountItem.setCabinClassName(StringUtils.isEmpty(shipReserveListDTO.getCabinClassName())?
                    shipReserveListDTO.getCabinClassStr():shipReserveListDTO.getCabinClassName());
            //服务费 = 預定服務費+稅費
            shipOrderAmountItem.setServiceAmount(shipOrderAmountItem.getServiceAmount()
                    .add(shipReserveDTO.getServicePrice()
                            .add(shipReserveDTO.getTaxPrice())));
            taxMap.put(shipReserveListDTO.getId(),shipReserveDTO.getServicePrice().add(shipReserveDTO.getTaxPrice()));
            touristSwitch.set(false);
            tripTypeFlag.incrementAndGet();
        }

        //新增旅客信息表價格信息
        updateTouristPrice(priceMap,taxMap,orderId);

        //产品ID拼接串
        String ids = productIds.substring(0, productIds.length() - 1);

        //2.插入订单信息
        saveOrderInfo(shipOrderReq, user, shipOrderAmountItem, adultTotalNumber.get(),
                childrenTotalNumber.get(), orderId, ids, tripTypeFlag, shipAllOrderDetailList);

        //3.插入保险信息
        saveInsuranceInfo(shipOrderReq,touristMap, user, orderId);

        return Result.success(orderId);
    }

    /**
     * 新增船票費和稅費
     * @param priceMap
     * @param taxMap
     * @param orderId
     */
    private void updateTouristPrice(Map<Long, Map<Integer, BigDecimal>> priceMap, Map<Long, BigDecimal> taxMap, Long orderId) {
        QueryWrapper<ShipOrderTourist> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ShipOrderTourist::getOrderId,orderId);
        List<ShipOrderTourist> shipOrderTourists = shipOrderTouristMapper.selectList(queryWrapper);
        if(CollectionUtil.isNotEmpty(shipOrderTourists)){
            for(ShipOrderTourist tourist : shipOrderTourists){

                Integer touristTypeId = tourist.getTouristTypeId();
                StringBuffer price = new StringBuffer();
                priceMap.forEach((k,y)->{
                    //價格=成本價+加幅費
                    BigDecimal bigDecimal = y.get(touristTypeId);
                    Map<String,BigDecimal> map = Maps.newHashMap();
                    map.put("price",bigDecimal);
                    map.put("tax",taxMap.get(k));
                    //船票價格/稅費
                    price.append(JSON.toJSONString(map) + "/");
                });

                if(price.length()-1 > 0){
                    tourist.setTicketPrice(price.substring(0,price.length()-1));
                    shipOrderTouristMapper.updateById(tourist);
                }
            }
        }
    }

    protected ShipProductIsRecommendedReq queryShipInfo(ShipOrderRouteProductReq orderRouteProductReq, ShipOrderRouteProductReq shipOrderRouteProductReq) {
        ShipProductIsRecommendedReq shipProductIsRecommendedReq = new ShipProductIsRecommendedReq();
        //查询产品信息
        List<ConditionDTO> conditionReqList = Lists.newArrayListWithExpectedSize(5);
        ShipReservationOrderReq shipReservationOrderReq = new ShipReservationOrderReq();
        ConditionDTO conditionDTO = new ConditionDTO();
        conditionDTO.setId(shipOrderRouteProductReq.getProductId());
        conditionDTO.setQueryDate(shipOrderRouteProductReq.getStartDate());
        conditionReqList.add(conditionDTO);
        shipReservationOrderReq.setConditionReqList(conditionReqList);
        List<ShipReservationGetOrderDTO> orderInfo = iShipProductService.getOrderInfo(shipReservationOrderReq);
        if(CollectionUtil.isNotEmpty(orderInfo)){
            ShipReservationGetOrderDTO dto = orderInfo.stream().findFirst().orElse(null);
            if(dto != null){
                shipProductIsRecommendedReq.setDepCityId(dto.getDepCityId());
                shipProductIsRecommendedReq.setArrCityId(dto.getArrCityId());
                shipProductIsRecommendedReq.setDepPlaceId(dto.getDepPlaceId());
                shipProductIsRecommendedReq.setId(Long.valueOf(shipOrderRouteProductReq.getProductId()));
                shipProductIsRecommendedReq.setArrPlaceId(dto.getArrPlaceId());
                shipProductIsRecommendedReq.setStartDate(shipOrderRouteProductReq.getStartDate());
                shipProductIsRecommendedReq.setCabinClass(String.valueOf(dto.getCabinClass()));
            }
        }
        shipProductIsRecommendedReq.setStartDate(orderRouteProductReq.getStartDate());
        shipProductIsRecommendedReq.setId(Long.valueOf(orderRouteProductReq.getProductId()));
        shipProductIsRecommendedReq.setTicketNumber(orderRouteProductReq.getTicketNumber());
        return shipProductIsRecommendedReq;
    }

    /**
     * 保存旅客信息
     * @param productId
     * @param user
     * @param touristMap
     * @param shipOrderAmountItem
     * @param adultTotalNumber
     * @param childrenTotalNumber
     * @param orderId
     * @param shipOrderTouristList
     * @param touristSwitch
     * @param shipReserveListDTO
     * @param startDate
     * @param priceMap
     * @return
     */
    private ShipReserveDTO saveOrderTouristInfo(String productId, TokenUser user, Map<Long, ShipOrderTourist> touristMap, ShipOrderAmountItem shipOrderAmountItem, AtomicInteger adultTotalNumber, AtomicInteger childrenTotalNumber, Long orderId, List<ShipOrderTouristReq> shipOrderTouristList, boolean touristSwitch, ShipReserveListDTO shipReserveListDTO, @NotNull(message = "出发时间不能为空") LocalDate startDate, Map<Long, Map<Integer, BigDecimal>> priceMap) {
        ShipReserveDTO shipReserveDTO = new ShipReserveDTO();
        BeanUtils.copyProperties(shipReserveListDTO, shipReserveDTO);
        //获取成本信息
        List<ConditionDTO> conditionReqList = Lists.newArrayListWithExpectedSize(5);
        ShipReservationOrderReq shipReservationOrderReq = new ShipReservationOrderReq();
        ConditionDTO conditionDTO = new ConditionDTO();
        conditionDTO.setId(productId);
        conditionDTO.setQueryDate(startDate);
        conditionReqList.add(conditionDTO);
        shipReservationOrderReq.setConditionReqList(conditionReqList);
        List<ShipReservationGetOrderDTO> orderInfo = iShipProductService.getOrderInfo(shipReservationOrderReq);
        Map<Integer,BigDecimal> map = Maps.newHashMap();

        //成本加+ 加辐费 + 税费 + 预订服务费
        BigDecimal adultPrice = new BigDecimal(0);
        BigDecimal childPrice = new BigDecimal(0);
        //成本加+ 加辐费
        BigDecimal beforeAdultPrice = new BigDecimal(0);
        BigDecimal beforeChildPrice = new BigDecimal(0);
        BigDecimal oldPrice = new BigDecimal(0);
        //稅費
        BigDecimal otherFeePrice = new BigDecimal(0);
        //預定服務費
        BigDecimal serviceFee = new BigDecimal(0);
        if(CollectionUtil.isNotEmpty(orderInfo)){
            ShipReservationGetOrderDTO dto = orderInfo.stream().findFirst().orElse(null);
            if(dto != null){
                adultPrice = dto.getAdultPrice();
                childPrice = dto.getChildPrice();
                beforeAdultPrice = dto.getBeforeAdultPrice();
                beforeChildPrice = dto.getBeforeChildPrice();
                oldPrice = dto.getBeforeOldPrice();
                otherFeePrice = dto.getOtherFeePrice();
            }
        }
        /**保存旅客信息 以及计算旅客成本*/
        for (ShipOrderTouristReq shipOrderTouristReq : shipOrderTouristList) {
            ShipOrderTourist shipOrderTourist = new ShipOrderTourist();
            long touristId = SnowflakeIdWorker.nextId();
            BeanUtils.copyProperties(shipOrderTouristReq, shipOrderTourist);
            shipOrderTourist.setId(touristId);
            shipOrderTourist.setOrderId(orderId);
            shipOrderTourist.setGmtCreate(LocalDateTime.now());
            shipOrderTourist.setCreateId(user.getId());

            //成人
            if(shipOrderTouristReq.getTouristTypeId() == 1){
                //成本價+加幅費
                shipOrderAmountItem.setAdultAmount(shipOrderAmountItem.getAdultAmount().add(beforeAdultPrice));
                //订单总额=成人價格+小童價格+...
                shipOrderAmountItem.setTotalAmount(shipOrderAmountItem.getTotalAmount().add(adultPrice));
                map.put(shipOrderTouristReq.getTouristTypeId(),beforeAdultPrice);
                adultTotalNumber.incrementAndGet();
            }
            //小童
            else if(shipOrderTouristReq.getTouristTypeId() == 2){
                //成本價+加幅費
                shipOrderAmountItem.setChildrenAmount(shipOrderAmountItem.getChildrenAmount().add(beforeChildPrice));
                //订单总额=成人價格+小童價格+...
                shipOrderAmountItem.setTotalAmount(shipOrderAmountItem.getTotalAmount().add(childPrice));
                map.put(shipOrderTouristReq.getTouristTypeId(),beforeChildPrice);
                childrenTotalNumber.incrementAndGet();
            }
            //長者 暫時不支持
//            else if(shipOrderTouristReq.getTouristTypeId() == 3){
//                shipOrderAmountItem.setOldAmount(shipOrderAmountItem.getOldAmount().add(oldPrice).add(serviceFee));
//            }
            //稅費
            shipOrderAmountItem.setChildrenTaxAmount(otherFeePrice);
            shipOrderAmountItem.setAdultTaxAmount(otherFeePrice);

            if (touristSwitch) {
                shipOrderTouristMapper.insert(shipOrderTourist);
                touristMap.put(Long.valueOf(shipOrderTouristReq.getTouristType()),shipOrderTourist);
            }
        }
        priceMap.put(Long.valueOf(productId),map);
        return shipReserveDTO;
    }


    /**
     *  保存订单的航线信息
     * @param user
     * @param adultAmount
     * @param childrenAmount
     * @param adultTaxAmount
     * @param childrenTaxAmount
     * @param orderId
     * @param shipAllOrderDetailList
     * @param shipOrderRouteProductReq
     * @param shipReserveListDTO
     * @param adultNumber
     * @param childrenNumber
     * @param shipReserveDTO
     */
    private void saveShipOrderRoute(TokenUser user, BigDecimal adultAmount, BigDecimal childrenAmount, BigDecimal adultTaxAmount, BigDecimal childrenTaxAmount, Long orderId, List<ShipOrderDetailListDTO> shipAllOrderDetailList, ShipOrderRouteProductReq shipOrderRouteProductReq, ShipReserveListDTO shipReserveListDTO, int adultNumber, int childrenNumber, ShipReserveDTO shipReserveDTO) {
        ShipOrderRouteReq shipOrderRouteReq = new ShipOrderRouteReq();
        BeanUtils.copyProperties(shipReserveDTO, shipOrderRouteReq);
        ShipOrderRoute shipOrderRoute = new ShipOrderRoute();
        BeanUtils.copyProperties(shipOrderRouteReq, shipOrderRoute);
        shipOrderRoute.setId(SnowflakeIdWorker.nextId());
        shipOrderRoute.setProductId(shipReserveListDTO.getId());
        shipOrderRoute.setOrderId(orderId);

        shipOrderRoute.setShipTypeName(shipReserveDTO.getShipTypeName());
        if(shipReserveDTO.getArrCityId() != null){
            shipOrderRoute.setArrCityId(Long.valueOf(shipReserveDTO.getArrCityId()));
        }
        if(shipReserveDTO.getDepCityId() != null){
            shipOrderRoute.setDepCityId(Long.valueOf(shipReserveDTO.getDepCityId()));
        }
        if(shipReserveDTO.getDepPlaceId() != null){
            shipOrderRoute.setDepPlaceId(Long.valueOf(shipReserveDTO.getDepPlaceId()));
        }
        if(shipReserveDTO.getArrPlaceId() != null){
            shipOrderRoute.setArrPlaceId(Long.valueOf(shipReserveDTO.getArrPlaceId()));
        }
        shipOrderRoute.setArrCityName(shipReserveDTO.getArrCityName());
        shipOrderRoute.setDepCityName(shipReserveDTO.getDepCityName());
        shipOrderRoute.setDepPlaceName(shipReserveDTO.getDepPlaceName());
        shipOrderRoute.setArrPlaceName(shipReserveDTO.getArrPlaceName());
        shipOrderRoute.setRouteName(shipReserveDTO.getRouteName());
        shipOrderRoute.setShipTypeName(shipReserveListDTO.getShipTypeName());

        if(shipReserveDTO.getCompanyType() != null){
            shipOrderRoute.setCompanyType(Long.valueOf(shipReserveDTO.getCompanyType()));
        }
        shipOrderRoute.setGmtCreate(LocalDateTime.now());
        shipOrderRoute.setCreateId(user.getId());
        shipOrderRoute.setNumber(shipOrderRouteProductReq.getTicketNumber());
        shipOrderRoute.setIsDeleted(ShipConstants.NOT_DELETE);
        //开船时间
        shipOrderRoute.setBeginTime(shipReserveListDTO.getDepTime());
        //出发时间
        shipOrderRoute.setDepTime(DateUtil.toLocalDateTime(shipOrderRouteProductReq.getStartDate()));

        shipOrderRoute.setCabinClassName(Objects.isNull(shipReserveListDTO.getCabinClassName()) ? shipReserveListDTO.getCabinClassStr() : shipReserveListDTO.getCabinClassName());
        List<ShipOrderDetailListDTO> shipOrderDetailList = computeAmount(adultAmount, childrenAmount, adultTaxAmount, childrenTaxAmount, adultNumber, childrenNumber, "HDK");
        shipOrderRoute.setOrderDetails(JSONUtil.toJsonStr(shipOrderDetailList));
        shipAllOrderDetailList.addAll(shipOrderDetailList);
        shipOrderRouteMapper.insert(shipOrderRoute);
    }


    /**
     * 产品库存
     * @param user                      用户信息
     * @param orderId                   订单ID
     * @param shipOrderRouteProductReq  航线信息
     * @param productId                 产品ID
     */
    private void saveSaleRecord(TokenUser user, Long orderId, ShipOrderRouteProductReq shipOrderRouteProductReq, Long productId) {
        /**保存产品库存售卖记录body*/
        ShipProductSaleRecordReq shipProductSaleRecordReq = new ShipProductSaleRecordReq();
        shipProductSaleRecordReq.setId(SnowflakeIdWorker.nextId());
        shipProductSaleRecordReq.setOrderId(orderId);
        shipProductSaleRecordReq.setProductId(productId);
        shipProductSaleRecordReq.setSalesDate(shipOrderRouteProductReq.getStartDate());
        shipProductSaleRecordReq.setSoldNumber(shipOrderRouteProductReq.getTicketNumber());
        //1:自营 2:代理商 3:官方渠道 4:第三方
        shipProductSaleRecordReq.setChannel(1);
        //1 线上 2线下
        shipProductSaleRecordReq.setLine(2);
        ////备注要加权限
//        shipProductSaleRecordReq.setCheckType(1);
        shipProductSaleRecordReq.setCustomId(user.getId());
        shipProductSaleRecordReq.setCustomName(user.getUsername());
        iShipProductSaleRecordService.insertRecord(shipProductSaleRecordReq, user);
    }


    /**
     * 插入保险信息
     * @param shipOrderReq  入参
     * @param touristMap
     * @param user          用户信息
     * @param orderId       订单ID
     */
    private void saveInsuranceInfo(ShipOrderReq shipOrderReq, Map<Long, ShipOrderTourist> touristMap, TokenUser user, Long orderId) {
        /**保险信息*/
        if (shipOrderReq.getBuyInsurance() != null && (shipOrderReq.getBuyInsurance().intValue() == NumberConstant.ONE.getValue().intValue())) {
            List<ShipOrderInsuranceReq> shipOrderInsuranceReqList = shipOrderReq.getShipOrderInsuranceReqList();
            if (CollectionUtil.isEmpty(shipOrderInsuranceReqList)) {
                new BusinessException(SystemError.AIR_ORDER_15005);
            }
            for (ShipOrderInsuranceReq shipOrderInsuranceReq : shipOrderInsuranceReqList) {
                ShipOrderInsurance shipOrderInsurance = new ShipOrderInsurance();
                BeanUtils.copyProperties(shipOrderInsuranceReq, shipOrderInsurance);
                shipOrderInsurance.setId(SnowflakeIdWorker.nextId());
                shipOrderInsurance.setOrderId(orderId);
                shipOrderInsurance.setCreateId(user.getId());

                //保险信息
                InsuranceDTO insuranceDto = notNull(iInsuranceService.detail(shipOrderInsuranceReq.getInsuranceId()), SystemError.CUSTOM_ORDER_4028);
                shipOrderInsurance.setInsuranceNumber(insuranceDto.getApiCode());
                shipOrderInsurance.setInsuranceName(insuranceDto.getName());

                //保险报价
                OfferReq offerReq = new OfferReq();
                Offer offer = new Offer();
                offer.setInsuranceId(shipOrderInsuranceReq.getInsuranceId());
                offer.setRiskCode(null);
                offer.setRationType(Assist.toInteger(insuranceDto.getRationType()));
                offer.setStarDate(DateUtil.fmtLocalDate(shipOrderInsuranceReq.getInsuranceStartDate().toLocalDate(), "yyyy-MM-dd"));
                offer.setEndDate(DateUtil.fmtLocalDate(shipOrderInsuranceReq.getInsuranceEndDate().toLocalDate(), "yyyy-MM-dd"));
                offerReq.setData(offer);
                try {
                    OfferDTO offerDto = iInsuranceService.acciQuotation(offerReq);
                    if (offerDto != null) {
                        shipOrderInsurance.setInsurancePrice(offerDto.getPremium());
                    }
                } catch (Exception e) {
                    log.error("保险服务调用异常");
                }

                //投保人
                if(touristMap.get(shipOrderInsuranceReq.getPolicyHolderId()) != null){
                    shipOrderInsurance.setPolicyHolderId(touristMap.get(shipOrderInsuranceReq.getPolicyHolderId()).getId());
                    shipOrderInsurance.setPolicyHolderName(touristMap.get(shipOrderInsuranceReq.getPolicyHolderId()).getTouristName());
                }
                //被保人
                if(StringUtil.isNotEmpty(shipOrderInsuranceReq.getInsuredPerson())){
                    String[] insuredPersons = shipOrderInsuranceReq.getInsuredPerson().split(",");
                    StringBuffer persons = new StringBuffer();
                    for(String insuredPersonId : insuredPersons){
                        if(touristMap.get(Long.valueOf(insuredPersonId)) != null){
                            persons.append(touristMap.get(Long.valueOf(insuredPersonId)).getId() + ",");
                        }
                    }
                    shipOrderInsurance.setInsuredPerson(persons.substring(0,persons.length()-1));
                }
                shipOrderInsurance.setGmtCreate(LocalDateTime.now());
                shipOrderInsurance.setIsDeleted(IsDeletedCode.NO.getCode());
                shipOrderInsuranceMapper.insert(shipOrderInsurance);
            }
        }
    }

    private void saveOrderInfo(ShipOrderReq shipOrderReq, TokenUser user, ShipOrderAmountItem shipOrderAmountItem, int adultTotalNumber, int childrenTotalNumber, Long orderId, String productIds, AtomicInteger tripTypeFlag, List<ShipOrderDetailListDTO> shipAllOrderDetailList) {
        BigDecimal serviceAmount = shipOrderAmountItem.getServiceAmount();
        BigDecimal totalAmount = shipOrderAmountItem.getTotalAmount();
        /**保存订单信息*/
        ShipOrder shipOrder = new ShipOrder();
        BeanUtils.copyProperties(shipOrderReq, shipOrder);
        //组装订单
        shipOrder.setId(orderId);
        shipOrder.setTripType(tripTypeFlag.get());//订单行程类型 1.单程 2往返
        shipOrder.setProductId(productIds);
        shipOrder.setGmtCreate(LocalDateTime.now());
        shipOrder.setCreateId(user.getId());
        shipOrder.setIsDeleted(ShipConstants.NOT_DELETE);
        //销售编号
        shipOrder.setOrderNumber(buildProductNumber(user.getId(), LocalDateTime.now()));

        // 计算付款到期时间,+30分钟
        shipOrder.setPayExpireDate(LocalDateTime.now().plusMinutes(30));
        //单服务费*面票数 次字段存稅費
        serviceAmount = serviceAmount.multiply(new BigDecimal(adultTotalNumber + childrenTotalNumber));
        shipOrder.setServiceFee(serviceAmount);
        //应收金额
        shipOrder.setReceivableAmount(totalAmount);
        //应收金额-优惠码-是否使用积分
        buildReceivableAmount(shipOrder,totalAmount);
        shipOrder.setContactName(shipOrderReq.getContactName());
        shipOrder.setPaymentStatus(OrderPaymentStatus.UN_PAYMENT.getCode()); //未付款
        shipOrder.setSalesmanId(user.getId());
        shipOrder.setSource(OrderSource.CPM.getCode());
        UserDTO userDTO = iSysUserService.loadUserByParam(user.getId(), 1);
        shipOrder.setSalesmanName(userDTO.getUsername());
        shipOrder.setSalesMethods(1);//销售方式(1：单品销售 2：打包销售)
        shipOrder.setProductType(1);//产品类型(1手工单，2外挂单)
        shipOrder.setCreateId(user.getId());
        shipOrder.setOrderDetails(JSONUtil.toJsonStr(shipAllOrderDetailList));
        shipOrder.setGmtCreate(LocalDateTime.now());

        if(shipOrderAmountItem.getDepCity().length() > 0){
            shipOrder.setDepCityName(shipOrderAmountItem.getDepCity().substring(0,shipOrderAmountItem.getDepCity().length()-1));
        }
        if(shipOrderAmountItem.getArrCity().length() > 0){
            shipOrder.setArrCityName(shipOrderAmountItem.getArrCity().substring(0,shipOrderAmountItem.getArrCity().length()-1));
        }
        if(shipOrderAmountItem.getDepPlace().length() > 0){
            shipOrder.setDepPlaceName(shipOrderAmountItem.getDepPlace().substring(0,shipOrderAmountItem.getDepPlace().length()-1));
        }
        if(shipOrderAmountItem.getArrPlace().length() > 0){
            shipOrder.setArrPlaceName(shipOrderAmountItem.getArrPlace().substring(0,shipOrderAmountItem.getArrPlace().length()-1));
        }
        if(shipOrderAmountItem.getVoyage().length() > 0){
            shipOrder.setVoyage(shipOrderAmountItem.getVoyage().substring(0,shipOrderAmountItem.getVoyage().length()-1));
        }
        if(!StringUtils.isEmpty(shipOrderAmountItem.getCabinClassName())){
            shipOrder.setCabinClassName(shipOrderAmountItem.getCabinClassName());
        }
        if(!StringUtils.isEmpty(shipOrderAmountItem.getCompanyType())){
            shipOrder.setCompanyType(shipOrderAmountItem.getCompanyType().substring(0,shipOrderAmountItem.getCompanyType().length()-1));
        }
        shipOrderMapper.insert(shipOrder);


        //过期取消订单 API定时任务
        try {
            // 下单完成后调用任务执行如果未付款则超时失效订单操作
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", orderId);
            // 延迟时间,单位毫秒,1800000L=30分钟后执行
            long delayMS = 1800000L;
            OhMyClient taskClient = new OhMyClient(domain, appName, password);
            ResultDTO<Long> resultTask = taskClient.runJob(jobId, jsonObject.toJSONString(), delayMS);

            if (resultTask.isSuccess()) {
                // 任务执行成功,过期时间*2是防止任务启动时redis数据已过期
                redisTemplate.opsForValue().set(RedisConstants.ORDER_INSTANCELD_KEY + orderId, resultTask.getData(), delayMS * 2, TimeUnit.MILLISECONDS);
            }
        } catch (Exception e) {
            log.error("当地玩乐订单-订单超时API任务错误");
        }
    }


    /**
     * 根据总价计算应收价格，减去会员积分和优惠券
     *
     * @param shipOrder
     * @param orderAmount
     */
    private void buildReceivableAmount(ShipOrder shipOrder, BigDecimal orderAmount) {
        BigDecimal receivableAmount = new BigDecimal(orderAmount.toString());
        //计算应收价格-是否使用积分
        if (shipOrder.getUsingPoints() != null) {
            BigDecimal usingPoints = new BigDecimal(String.valueOf(shipOrder.getUsingPoints()));
            // 校验会员积分是否充足
//            checkMemberPoints(shipOrder, usingPoints);
            //计算应收价格-计算积分
            BigDecimal usingPointsCNY = usingPoints.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
            //人民币兑港币
            BigDecimal crmExchangeRate = getCrmExchangeRateByName(Currency.CNY.getSymbol());
            BigDecimal usingPointsHKD = usingPointsCNY.multiply(crmExchangeRate);
            if (receivableAmount.compareTo(usingPointsHKD) < 0) {
                // 总价减去积分价后为负数，不予许提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
            }
            receivableAmount = receivableAmount.subtract(usingPointsHKD);
        }
        //计算应收价格-计算推广码（优惠券）
//        if (shipOrder.getCouponId() != null) {
//            // do something 推广码接口未写完，等待中
////            OperatePromotionQueryReq operatePromotionQueryReq = new OperatePromotionQueryReq();
////            operatePromotionQueryReq.setId(airportExpressOrder.getCouponId());
////            Result<OperatePromotionQueryDTO> operatePromotionQueryDTOResult = operatePromotionService.query(operatePromotionQueryReq);
//        }
        shipOrder.setOrderAmount(receivableAmount);
    }

    /**
     * 根据当前用户去查找对应的用户权限
     *
     * @param id
     * @return
     */
    private List<String> getUserIdsByUserId(Long id) {
        List<Long> longs = iSysDepartmentService.queryIdsByUserId(id);
        longs.add(id);
        String stringBuffer = "";
        for (Long aLong : longs) {
            stringBuffer += aLong.toString() + ",";
        }
        if (!"".equals(stringBuffer)) {
            stringBuffer = stringBuffer.substring(0, stringBuffer.length() - 1);
        }
        return Lists.newArrayList(stringBuffer.split(","));
    }

    /**
     * 校验积分是否充足
     *
     * @param shipOrder
     * @param usingPoints
     */
    private void checkMemberPoints(ShipOrder shipOrder, BigDecimal usingPoints) {
        ContactQueryDTO contactQuery;
        try {
            CrmMemberQueryReq crmMemberQueryReq = new CrmMemberQueryReq(1, shipOrder.getMemberId().toString(), null);
            contactQuery = crmMemberService.queryMember(crmMemberQueryReq);
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw e;
            } else {
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
            }
        }
        BigDecimal findMemberPoints = new BigDecimal(String.valueOf(contactQuery.getMember().getPoint1Value()));
        if (findMemberPoints.compareTo(usingPoints) < 0) {
            // 会员积分不足
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60008);
        }
    }

    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private BigDecimal getCrmExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = iMainDataCurrencyService.list(mainDataCurrencyListReq);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0).getCrmExchangeRate();
    }

    private List<ShipOrderDetailListDTO> computeAmount(BigDecimal adultAmount, BigDecimal childrenAmount, BigDecimal adultTaxAmount,
                                                       BigDecimal childrenTaxAmount, int adultNumber, int childrenNumber, String currency) {
        List<ShipOrderDetailListDTO> ShipOrderDetailList = new ArrayList<>();
        //合计成json
        if (adultNumber > 0) {
            List<ShipOrderDetailItemDTO> ShipOrderDetailItemList = new ArrayList<>();
            ShipOrderDetailItemDTO shipOrderDetailItemDTO = new ShipOrderDetailItemDTO();
            ShipOrderDetailListDTO shipOrderDetailListDTO = new ShipOrderDetailListDTO();
            shipOrderDetailListDTO.setTitle("成人船票总额");
            shipOrderDetailItemDTO.setTitle("成人票价");
            shipOrderDetailItemDTO.setNumber(adultNumber);
            shipOrderDetailItemDTO.setPrice(adultAmount);
            shipOrderDetailItemDTO.setCurrency(currency);
            ShipOrderDetailItemList.add(shipOrderDetailItemDTO);
            shipOrderDetailItemDTO = new ShipOrderDetailItemDTO();
            shipOrderDetailItemDTO.setTitle("稅與費用");
            shipOrderDetailItemDTO.setNumber(adultNumber);
            shipOrderDetailItemDTO.setPrice(adultTaxAmount);
            shipOrderDetailItemDTO.setCurrency(currency);
            ShipOrderDetailItemList.add(shipOrderDetailItemDTO);
            shipOrderDetailListDTO.setShipOrderDetailItemList(ShipOrderDetailItemList);
            ShipOrderDetailList.add(shipOrderDetailListDTO);
        }
        if (childrenNumber > 0) {
            List<ShipOrderDetailItemDTO> ShipOrderDetailItemList = new ArrayList<>();
            ShipOrderDetailItemDTO shipOrderDetailItemDTO = new ShipOrderDetailItemDTO();
            ShipOrderDetailListDTO shipOrderDetailListDTO = new ShipOrderDetailListDTO();
            shipOrderDetailListDTO.setTitle("小童船票总额");
            shipOrderDetailItemDTO.setTitle("小童票价");
            shipOrderDetailItemDTO.setNumber(childrenNumber);
            shipOrderDetailItemDTO.setPrice(childrenAmount);
            shipOrderDetailItemDTO.setCurrency(currency);
            ShipOrderDetailItemList.add(shipOrderDetailItemDTO);
            shipOrderDetailItemDTO = new ShipOrderDetailItemDTO();
            shipOrderDetailItemDTO.setTitle("稅與費用");
            shipOrderDetailItemDTO.setNumber(childrenNumber);
            shipOrderDetailItemDTO.setPrice(childrenTaxAmount);
            shipOrderDetailItemDTO.setCurrency(currency);
            ShipOrderDetailItemList.add(shipOrderDetailItemDTO);
            shipOrderDetailListDTO.setShipOrderDetailItemList(ShipOrderDetailItemList);
            ShipOrderDetailList.add(shipOrderDetailListDTO);
        }
        return ShipOrderDetailList;
    }

    private BigDecimal computeOffLinePrice(com.ctshk.rpc.ship.dto.ShipReserveDTO shipProductReserveDTO, BigDecimal costPrice) {
        BigDecimal offLinePrice = new BigDecimal(0);
        if (shipProductReserveDTO.getAdjustType() == com.ctshk.rpc.ship.dto.ShipConstants.ADJUST_TYPE_PERCENT) {
            double percent = shipProductReserveDTO.getPercent();
            percent = percent * 0.01;
            offLinePrice = costPrice.multiply(new BigDecimal(percent)).setScale(0, BigDecimal.ROUND_HALF_UP);
        } else if (shipProductReserveDTO.getAdjustType() == com.ctshk.rpc.ship.dto.ShipConstants.ADJUST_TYPE_AMOUNT) {
            offLinePrice = shipProductReserveDTO.getOffLinePrice();
        }
        return offLinePrice;
    }

    /**
     * 银行优惠工具类
     */
    private BigDecimal getAmountByBankReference(ShipOrder shipOrder, Long unionpayDiscountId) {
        OperateBankConformQueryReq operateBankConformQueryReq = new OperateBankConformQueryReq();
        operateBankConformQueryReq.setId(unionpayDiscountId);
        Result<OperateBankPreferenceQueryDTO> operateBankPreferenceQueryDTOResult = operateBankPreferenceService.queryConform(operateBankConformQueryReq);
        if (!operateBankPreferenceQueryDTOResult.isSuccess()) {
            // 校验银行优惠不满足条件
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60018);
        }
        OperateBankPreferenceQueryDTO bankQueryDto = operateBankPreferenceQueryDTOResult.getData();
        if (bankQueryDto.getDiscountType() == 1) {
            // 校验应收价格是否符合满减优惠
            if (shipOrder.getReceivableAmount().compareTo(bankQueryDto.getFullAmount()) >= 0) {
                return bankQueryDto.getReductionAmount();
            } else {
                // 校验银行优惠不满足条件
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60018);
            }
        } else {
            // 使用百分比优惠
            BigDecimal currentAmount = shipOrder.getReceivableAmount().multiply(new BigDecimal(String.valueOf(bankQueryDto.getDiscountPercent())));
            return currentAmount.compareTo(bankQueryDto.getMaxDiscount()) > 0 ? bankQueryDto.getMaxDiscount() : currentAmount;
        }
    }

    /**
     * C+員工編號+月日4位+時分4位+4位隨機數字
     *
     * @param userId
     * @return
     */
    private String buildProductNumber(Long userId, LocalDateTime nowLocalDateTime) {
        UserDTO userDTO = sysUserService.loadUserByParam(userId, 1);
        String employeeNumber = userDTO.getEmployeeNumber();
        String monthCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMonthValue()), 2, "0");
        String dayCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getDayOfMonth()), 2, "0");
        String hourCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getHour()), 2, "0");
        String minuteCode = org.apache.commons.lang3.StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMinute()), 2, "0");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("C").append(employeeNumber).append(monthCode).append(dayCode).append(hourCode).append(minuteCode).append(randomNumber);
        return orderNumberSb.toString();
    }
}
